Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/DominicBurkart/turbolift in…
Browse files Browse the repository at this point in the history
…to main
  • Loading branch information
DominicBurkart committed Dec 5, 2021
2 parents a591ee3 + 15824c5 commit 115b9ff
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 67 deletions.
34 changes: 7 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[![last commit](https://img.shields.io/github/last-commit/dominicburkart/turbolift)](https://github.com/DominicBurkart/turbolift)
[![website](https://img.shields.io/badge/-website-blue)](https://dominic.computer/turbolift)

Turbolift is a distribution interface for rust. It's designed to make
Turbolift is a prototype distribution interface for rust. It's designed to make
distribution easier and more maintainable by extracting and distributing specific
functions and their dependencies from a larger rust application.
Turbolift then acts as the glue between these extracted mini-apps and
Expand All @@ -16,40 +16,28 @@ Look in the [examples](https://github.com/DominicBurkart/turbolift/tree/main/exa
directory for full projects with working syntax examples. An [external example](https://github.com/DominicBurkart/turbolift_example)
is maintained that can be used as a template repo.

## Distribution as an afterthought
## Notes

Turbolift allows developers to turn normal rust functions into distributed services
just by tagging them with a macro. Right now, Turbolift only works with K8s, though
it's designed to be extended to other cluster management utilities.

## Orchestration with a feature flag

Distribution is feature-gated in Turbolift, so it's easy to activate distribution
for some builds and deactivate it for others (while developing locally, for
example).

## Important implementation notes

- implemented over http using `reqwest` and `actix-web` (no current plans to
- Turbolift works as a proof-of-concept, but has not been optimized to shrink compilation time/requirements.
- Distribution is feature-gated in Turbolift to facilitate development / conditional distribution. The feature is called "distributed."
- Turbolift is implemented over http using `reqwest` and `actix-web` (no current plans to
refactor to use a lower level network protocol).
- assumes a secure network– function parameters are sent in plaintext to the
- Turbolift assumes a secure network– function parameters are sent in plaintext to the
microservice.
- source vulnerability: when building, anything in the project directory or in
- When building, anything in the project directory or in
local dependencies declared in the project manifest could be bundled and sent
over the network to workers.

More information is available on the [project homepage](https://dominic.computer/turbolift).

## Current Limitations

- DO NOT RUN TURBOLIFT ON A PUBLIC-FACING CLUSTER.
- *Because of reliance on unstable proc_macro::Span features, all programs
using turbolift need to be built with an unstable nightly compiler flag (e.g.
`RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo build`)*
([tracking issue](https://github.com/rust-lang/rust/issues/54725)).
- Functions are assumed to be pure (lacking side-effects such as
writing to the file system or mutation of a global variable).
*Today, this is not enforced by the code.*
- For a function to be distributed, its inputs and outputs have to be
(de)serializable with [Serde](https://github.com/serde-rs/serde).
- Distributed functions cannot be nested in other functions.
Expand Down Expand Up @@ -82,11 +70,3 @@ readiness check instead of just sleeping ([code location](https://github.com/Dom
tagged function into an async function (to provide an identical API), but
don't build any microservices or alter any code.
- [ ] build cross-architecture compilation tests into the CI.

## Current tech debt todo

- [ ] start reducing ginormous API, right now basically everything is public
- [ ] refactor split between turbolift_internals and turbolift_macros
- [ ] improve names
- [ ] send params in json as payload instead of directly in the url
- [ ] we need to do a better job of cleaning up docker images, locally and in the cluster.
1 change: 1 addition & 0 deletions examples/kubernetes_example/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![feature(async_closure)] // not actually necessary, just added to test that feature defs work.
#[macro_use]
extern crate lazy_static;
#[macro_use(c)]
Expand Down
1 change: 1 addition & 0 deletions examples/local_queue_example/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![feature(async_closure)] // not actually necessary, just added to test that feature defs work.
extern crate proc_macro;
use futures::future::try_join_all;
use rand;
Expand Down
75 changes: 35 additions & 40 deletions turbolift_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,59 +74,54 @@ pub fn on(distribution_platform_: TokenStream, function_: TokenStream) -> TokenS
let sanitized_file = extract_function::get_sanitized_file(&function);
// todo make code below hygienic in case sanitized_file also imports from actix_web
let main_file = q! {
use turbolift::actix_web::{self, get, web, HttpResponse, HttpRequest, Result, Responder};
#sanitized_file
use turbolift::tokio_compat_02::FutureExt;

#sanitized_file
#dummy_function
#target_function

#[get("/health-probe")]
async fn health_probe(_req: HttpRequest) -> impl Responder {
HttpResponse::Ok()
async fn health_probe(_req: turbolift::actix_web::HttpRequest) -> impl turbolift::actix_web::Responder {
turbolift::actix_web::HttpResponse::Ok()
}

#[get(#wrapper_route)]
#[turbolift::tracing::instrument]
async fn turbolift_wrapper(web::Path((#untyped_params_tokens_with_run_id)): web::Path<(#param_types)>) -> Result<HttpResponse> {
Ok(
HttpResponse::Ok()
.json(#function_name(#untyped_params_tokens))
)
async fn turbolift_wrapper(turbolift::actix_web::web::Path((#untyped_params_tokens_with_run_id)): turbolift::actix_web::web::Path<(#param_types)>) -> impl turbolift::actix_web::Responder {
turbolift::actix_web::HttpResponse::Ok()
.json(#function_name(#untyped_params_tokens))
}

#[actix_web::main]
#[turbolift::tracing::instrument]
async fn main() -> std::io::Result<()> {
use actix_web::{App, HttpServer, HttpRequest, web};

let args: Vec<String> = std::env::args().collect();
let ip_and_port = &args[1];
turbolift::tracing::info!("service main() started. ip_and_port parsed.");
HttpServer::new(
||
App::new()
.service(
turbolift_wrapper
)
.service(
health_probe
)
.default_service(
web::get()
.to(
|req: HttpRequest|
HttpResponse::NotFound().body(
format!("endpoint not found: {}", req.uri())
fn main() {
turbolift::actix_web::rt::System::new("main".to_string())
.block_on(async move {
let args: Vec<String> = std::env::args().collect();
let ip_and_port = &args[1];
turbolift::tracing::info!("service main() started. ip_and_port parsed.");
turbolift::actix_web::HttpServer::new(
||
turbolift::actix_web::App::new()
.route(
#wrapper_route, turbolift::actix_web::web::get().to(turbolift_wrapper)
)
.route(
"/health-probe", turbolift::actix_web::web::get().to(health_probe)
)
.default_service(
turbolift::actix_web::web::get()
.to(
|req: turbolift::actix_web::HttpRequest|
turbolift::actix_web::HttpResponse::NotFound().body(
format!("endpoint not found: {}", req.uri())
)
)
)
)
)
.bind(ip_and_port)?
.run()
.compat()
.await
}
)
.bind(ip_and_port)?
.run()
.compat()
.await
}).unwrap();
}
};

// copy all files in repo into cache
Expand Down

0 comments on commit 115b9ff

Please sign in to comment.