Job

Trait Job 

Source
pub trait Job<T, Ctx>:
    Sized
    + Clone
    + Send
    + Sync
    + 'static {
    type Future: Future<Output = Option<JobResult>> + Send + 'static;

    // Required method
    fn call(self, call: JobCall, ctx: Ctx) -> Self::Future;

    // Provided methods
    fn layer<L>(self, layer: L) -> Layered<L, Self, T, Ctx>
       where L: Layer<JobService<Self, T, Ctx>> + Clone,
             <L as Layer<JobService<Self, T, Ctx>>>::Service: Service<JobCall> { ... }
    fn with_context(self, ctx: Ctx) -> JobService<Self, T, Ctx> { ... }
}
Expand description

Trait for async functions that can be used to handle requests.

You shouldn’t need to depend on this trait directly. It is automatically implemented for functions of the right types.

See the module docs for more details.

§Converting Jobs into Services

To convert Jobs into Services you have to call either JobWithoutContextExt::into_service or Job::with_context:

use blueprint_sdk::extract::Context;
use blueprint_sdk::job::JobWithoutContextExt;
use blueprint_sdk::{Job, JobCall};
use tower::Service;

// this job doesn't require any state
async fn one() {}
// so it can be converted to a service with `JobWithoutContextExt::into_service`
assert_service(one.into_service());

// this job requires a context
async fn two(_: Context<String>) {}
// so we have to provide it
let job_with_state = two.with_context(String::new());
// which gives us a `Service`
assert_service(job_with_state);

// helper to check that a value implements `Service`
fn assert_service<S>(service: S)
where
    S: Service<JobCall>,
{
}

§Debugging job type errors

For a function to be used as a job it must implement the Job trait. blueprint-sdk provides blanket implementations for functions that:

  • Are async fns.
  • Take no more than 16 arguments that all implement Send.
  • Returns something that implements IntoJobResult.
  • If a closure is used it must implement Clone + Send and be 'static.
  • Returns a future that is Send. The most common way to accidentally make a future !Send is to hold a !Send type across an await.

Unfortunately Rust gives poor error messages if you try to use a function that doesn’t quite match what’s required by Job.

You might get an error like this:

error[E0277]: the trait bound `fn(u64) -> u64 {job}: blueprint_sdk::Job<_, _>` is not satisfied
  --> src/main.rs:48:40
   |
48 |                 .route(MY_JOB_ID, job)
   |                  -----            ^^^ the trait `blueprint_sdk::Job<_, _>` is not implemented for fn item `fn(u64) -> u64 {job}`
   |                  |
   |                  required by a bound introduced by this call
   |
   = note: Consider using `#[blueprint_sdk::debug_job]` to improve the error message
   = help: the trait `blueprint_sdk::Job<T, Ctx>` is implemented for `blueprint_sdk::job::Layered<L, J, T, Ctx>`

This error doesn’t tell you why your function doesn’t implement Job. It’s possible to improve the error with the debug_job proc-macro from the blueprint-macros crate.

§Jobs that aren’t functions

The Job trait is also implemented for T: IntoJobResult. That allows easily returning fixed data for routes:

use blueprint_sdk::Router;
use serde_json::json;

const HELLO_JOB_ID: u32 = 0;
const USERS_JOB_ID: u32 = 1;

let app = Router::new()
    // respond with a fixed string
    .route(HELLO_JOB_ID, "Hello, World!")
    // or return some mock data
    .route(USERS_JOB_ID, json!({ "id": 1, "username": "alice" }).to_string());

Required Associated Types§

Source

type Future: Future<Output = Option<JobResult>> + Send + 'static

The type of future calling this job returns.

Required Methods§

Source

fn call(self, call: JobCall, ctx: Ctx) -> Self::Future

Call the job with the given request.

Provided Methods§

Source

fn layer<L>(self, layer: L) -> Layered<L, Self, T, Ctx>
where L: Layer<JobService<Self, T, Ctx>> + Clone, <L as Layer<JobService<Self, T, Ctx>>>::Service: Service<JobCall>,

Apply a tower::Layer to the job.

All requests to the job will be processed by the layer’s corresponding middleware.

This can be used to add additional processing to a request for a single job.

Note this differs from routing::Router::layer which adds a middleware to a group of routes.

If you’re applying middleware that produces errors you have to handle the errors so they’re converted into responses. You can learn more about doing that here.

§Example

Adding the tower::limit::ConcurrencyLimit middleware to a job can be done like so:

use blueprint_sdk::{Job, Router};
use tower::limit::{ConcurrencyLimit, ConcurrencyLimitLayer};

async fn job() { /* ... */
}

const MY_JOB_ID: u32 = 0;

let layered_job = job.layer(ConcurrencyLimitLayer::new(64));
let app = Router::new().route(MY_JOB_ID, layered_job);
Source

fn with_context(self, ctx: Ctx) -> JobService<Self, T, Ctx>

Convert the job into a Service by providing the context

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§

Source§

impl<F, Fut, Ctx, Res, M, T1> Job<(M, T1), Ctx> for F
where F: FnOnce(T1) -> Fut + Clone + Send + Sync + 'static, Fut: Future<Output = Res> + Send, Ctx: Send + Sync + 'static, Res: IntoJobResult, T1: FromJobCall<Ctx, M> + Send,

Source§

type Future = Pin<Box<dyn Future<Output = Option<JobResult>> + Send>>

Source§

impl<F, Fut, Ctx, Res, M, T1, T2> Job<(M, T1, T2), Ctx> for F
where F: FnOnce(T1, T2) -> Fut + Clone + Send + Sync + 'static, Fut: Future<Output = Res> + Send, Ctx: Send + Sync + 'static, Res: IntoJobResult, T1: FromJobCallParts<Ctx> + Send, T2: FromJobCall<Ctx, M> + Send,

Source§

type Future = Pin<Box<dyn Future<Output = Option<JobResult>> + Send>>

Source§

impl<F, Fut, Ctx, Res, M, T1, T2, T3> Job<(M, T1, T2, T3), Ctx> for F
where F: FnOnce(T1, T2, T3) -> Fut + Clone + Send + Sync + 'static, Fut: Future<Output = Res> + Send, Ctx: Send + Sync + 'static, Res: IntoJobResult, T1: FromJobCallParts<Ctx> + Send, T2: FromJobCallParts<Ctx> + Send, T3: FromJobCall<Ctx, M> + Send,

Source§

type Future = Pin<Box<dyn Future<Output = Option<JobResult>> + Send>>

Source§

impl<F, Fut, Ctx, Res, M, T1, T2, T3, T4> Job<(M, T1, T2, T3, T4), Ctx> for F
where F: FnOnce(T1, T2, T3, T4) -> Fut + Clone + Send + Sync + 'static, Fut: Future<Output = Res> + Send, Ctx: Send + Sync + 'static, Res: IntoJobResult, T1: FromJobCallParts<Ctx> + Send, T2: FromJobCallParts<Ctx> + Send, T3: FromJobCallParts<Ctx> + Send, T4: FromJobCall<Ctx, M> + Send,

Source§

type Future = Pin<Box<dyn Future<Output = Option<JobResult>> + Send>>

Source§

impl<F, Fut, Ctx, Res, M, T1, T2, T3, T4, T5> Job<(M, T1, T2, T3, T4, T5), Ctx> for F
where F: FnOnce(T1, T2, T3, T4, T5) -> Fut + Clone + Send + Sync + 'static, Fut: Future<Output = Res> + Send, Ctx: Send + Sync + 'static, Res: IntoJobResult, T1: FromJobCallParts<Ctx> + Send, T2: FromJobCallParts<Ctx> + Send, T3: FromJobCallParts<Ctx> + Send, T4: FromJobCallParts<Ctx> + Send, T5: FromJobCall<Ctx, M> + Send,

Source§

type Future = Pin<Box<dyn Future<Output = Option<JobResult>> + Send>>

Source§

impl<F, Fut, Ctx, Res, M, T1, T2, T3, T4, T5, T6> Job<(M, T1, T2, T3, T4, T5, T6), Ctx> for F
where F: FnOnce(T1, T2, T3, T4, T5, T6) -> Fut + Clone + Send + Sync + 'static, Fut: Future<Output = Res> + Send, Ctx: Send + Sync + 'static, Res: IntoJobResult, T1: FromJobCallParts<Ctx> + Send, T2: FromJobCallParts<Ctx> + Send, T3: FromJobCallParts<Ctx> + Send, T4: FromJobCallParts<Ctx> + Send, T5: FromJobCallParts<Ctx> + Send, T6: FromJobCall<Ctx, M> + Send,

Source§

type Future = Pin<Box<dyn Future<Output = Option<JobResult>> + Send>>

Source§

impl<F, Fut, Ctx, Res, M, T1, T2, T3, T4, T5, T6, T7> Job<(M, T1, T2, T3, T4, T5, T6, T7), Ctx> for F
where F: FnOnce(T1, T2, T3, T4, T5, T6, T7) -> Fut + Clone + Send + Sync + 'static, Fut: Future<Output = Res> + Send, Ctx: Send + Sync + 'static, Res: IntoJobResult, T1: FromJobCallParts<Ctx> + Send, T2: FromJobCallParts<Ctx> + Send, T3: FromJobCallParts<Ctx> + Send, T4: FromJobCallParts<Ctx> + Send, T5: FromJobCallParts<Ctx> + Send, T6: FromJobCallParts<Ctx> + Send, T7: FromJobCall<Ctx, M> + Send,

Source§

type Future = Pin<Box<dyn Future<Output = Option<JobResult>> + Send>>

Source§

impl<F, Fut, Ctx, Res, M, T1, T2, T3, T4, T5, T6, T7, T8> Job<(M, T1, T2, T3, T4, T5, T6, T7, T8), Ctx> for F
where F: FnOnce(T1, T2, T3, T4, T5, T6, T7, T8) -> Fut + Clone + Send + Sync + 'static, Fut: Future<Output = Res> + Send, Ctx: Send + Sync + 'static, Res: IntoJobResult, T1: FromJobCallParts<Ctx> + Send, T2: FromJobCallParts<Ctx> + Send, T3: FromJobCallParts<Ctx> + Send, T4: FromJobCallParts<Ctx> + Send, T5: FromJobCallParts<Ctx> + Send, T6: FromJobCallParts<Ctx> + Send, T7: FromJobCallParts<Ctx> + Send, T8: FromJobCall<Ctx, M> + Send,

Source§

type Future = Pin<Box<dyn Future<Output = Option<JobResult>> + Send>>

Source§

impl<F, Fut, Ctx, Res, M, T1, T2, T3, T4, T5, T6, T7, T8, T9> Job<(M, T1, T2, T3, T4, T5, T6, T7, T8, T9), Ctx> for F
where F: FnOnce(T1, T2, T3, T4, T5, T6, T7, T8, T9) -> Fut + Clone + Send + Sync + 'static, Fut: Future<Output = Res> + Send, Ctx: Send + Sync + 'static, Res: IntoJobResult, T1: FromJobCallParts<Ctx> + Send, T2: FromJobCallParts<Ctx> + Send, T3: FromJobCallParts<Ctx> + Send, T4: FromJobCallParts<Ctx> + Send, T5: FromJobCallParts<Ctx> + Send, T6: FromJobCallParts<Ctx> + Send, T7: FromJobCallParts<Ctx> + Send, T8: FromJobCallParts<Ctx> + Send, T9: FromJobCall<Ctx, M> + Send,

Source§

type Future = Pin<Box<dyn Future<Output = Option<JobResult>> + Send>>

Source§

impl<F, Fut, Ctx, Res, M, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> Job<(M, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10), Ctx> for F
where F: FnOnce(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) -> Fut + Clone + Send + Sync + 'static, Fut: Future<Output = Res> + Send, Ctx: Send + Sync + 'static, Res: IntoJobResult, T1: FromJobCallParts<Ctx> + Send, T2: FromJobCallParts<Ctx> + Send, T3: FromJobCallParts<Ctx> + Send, T4: FromJobCallParts<Ctx> + Send, T5: FromJobCallParts<Ctx> + Send, T6: FromJobCallParts<Ctx> + Send, T7: FromJobCallParts<Ctx> + Send, T8: FromJobCallParts<Ctx> + Send, T9: FromJobCallParts<Ctx> + Send, T10: FromJobCall<Ctx, M> + Send,

Source§

type Future = Pin<Box<dyn Future<Output = Option<JobResult>> + Send>>

Source§

impl<F, Fut, Ctx, Res, M, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Job<(M, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11), Ctx> for F
where F: FnOnce(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) -> Fut + Clone + Send + Sync + 'static, Fut: Future<Output = Res> + Send, Ctx: Send + Sync + 'static, Res: IntoJobResult, T1: FromJobCallParts<Ctx> + Send, T2: FromJobCallParts<Ctx> + Send, T3: FromJobCallParts<Ctx> + Send, T4: FromJobCallParts<Ctx> + Send, T5: FromJobCallParts<Ctx> + Send, T6: FromJobCallParts<Ctx> + Send, T7: FromJobCallParts<Ctx> + Send, T8: FromJobCallParts<Ctx> + Send, T9: FromJobCallParts<Ctx> + Send, T10: FromJobCallParts<Ctx> + Send, T11: FromJobCall<Ctx, M> + Send,

Source§

type Future = Pin<Box<dyn Future<Output = Option<JobResult>> + Send>>

Source§

impl<F, Fut, Ctx, Res, M, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Job<(M, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12), Ctx> for F
where F: FnOnce(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) -> Fut + Clone + Send + Sync + 'static, Fut: Future<Output = Res> + Send, Ctx: Send + Sync + 'static, Res: IntoJobResult, T1: FromJobCallParts<Ctx> + Send, T2: FromJobCallParts<Ctx> + Send, T3: FromJobCallParts<Ctx> + Send, T4: FromJobCallParts<Ctx> + Send, T5: FromJobCallParts<Ctx> + Send, T6: FromJobCallParts<Ctx> + Send, T7: FromJobCallParts<Ctx> + Send, T8: FromJobCallParts<Ctx> + Send, T9: FromJobCallParts<Ctx> + Send, T10: FromJobCallParts<Ctx> + Send, T11: FromJobCallParts<Ctx> + Send, T12: FromJobCall<Ctx, M> + Send,

Source§

type Future = Pin<Box<dyn Future<Output = Option<JobResult>> + Send>>

Source§

impl<F, Fut, Ctx, Res, M, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Job<(M, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13), Ctx> for F
where F: FnOnce(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) -> Fut + Clone + Send + Sync + 'static, Fut: Future<Output = Res> + Send, Ctx: Send + Sync + 'static, Res: IntoJobResult, T1: FromJobCallParts<Ctx> + Send, T2: FromJobCallParts<Ctx> + Send, T3: FromJobCallParts<Ctx> + Send, T4: FromJobCallParts<Ctx> + Send, T5: FromJobCallParts<Ctx> + Send, T6: FromJobCallParts<Ctx> + Send, T7: FromJobCallParts<Ctx> + Send, T8: FromJobCallParts<Ctx> + Send, T9: FromJobCallParts<Ctx> + Send, T10: FromJobCallParts<Ctx> + Send, T11: FromJobCallParts<Ctx> + Send, T12: FromJobCallParts<Ctx> + Send, T13: FromJobCall<Ctx, M> + Send,

Source§

type Future = Pin<Box<dyn Future<Output = Option<JobResult>> + Send>>

Source§

impl<F, Fut, Ctx, Res, M, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> Job<(M, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14), Ctx> for F
where F: FnOnce(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) -> Fut + Clone + Send + Sync + 'static, Fut: Future<Output = Res> + Send, Ctx: Send + Sync + 'static, Res: IntoJobResult, T1: FromJobCallParts<Ctx> + Send, T2: FromJobCallParts<Ctx> + Send, T3: FromJobCallParts<Ctx> + Send, T4: FromJobCallParts<Ctx> + Send, T5: FromJobCallParts<Ctx> + Send, T6: FromJobCallParts<Ctx> + Send, T7: FromJobCallParts<Ctx> + Send, T8: FromJobCallParts<Ctx> + Send, T9: FromJobCallParts<Ctx> + Send, T10: FromJobCallParts<Ctx> + Send, T11: FromJobCallParts<Ctx> + Send, T12: FromJobCallParts<Ctx> + Send, T13: FromJobCallParts<Ctx> + Send, T14: FromJobCall<Ctx, M> + Send,

Source§

type Future = Pin<Box<dyn Future<Output = Option<JobResult>> + Send>>

Source§

impl<F, Fut, Ctx, Res, M, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> Job<(M, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15), Ctx> for F
where F: FnOnce(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15) -> Fut + Clone + Send + Sync + 'static, Fut: Future<Output = Res> + Send, Ctx: Send + Sync + 'static, Res: IntoJobResult, T1: FromJobCallParts<Ctx> + Send, T2: FromJobCallParts<Ctx> + Send, T3: FromJobCallParts<Ctx> + Send, T4: FromJobCallParts<Ctx> + Send, T5: FromJobCallParts<Ctx> + Send, T6: FromJobCallParts<Ctx> + Send, T7: FromJobCallParts<Ctx> + Send, T8: FromJobCallParts<Ctx> + Send, T9: FromJobCallParts<Ctx> + Send, T10: FromJobCallParts<Ctx> + Send, T11: FromJobCallParts<Ctx> + Send, T12: FromJobCallParts<Ctx> + Send, T13: FromJobCallParts<Ctx> + Send, T14: FromJobCallParts<Ctx> + Send, T15: FromJobCall<Ctx, M> + Send,

Source§

type Future = Pin<Box<dyn Future<Output = Option<JobResult>> + Send>>

Source§

impl<F, Fut, Ctx, Res, M, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> Job<(M, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16), Ctx> for F
where F: FnOnce(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16) -> Fut + Clone + Send + Sync + 'static, Fut: Future<Output = Res> + Send, Ctx: Send + Sync + 'static, Res: IntoJobResult, T1: FromJobCallParts<Ctx> + Send, T2: FromJobCallParts<Ctx> + Send, T3: FromJobCallParts<Ctx> + Send, T4: FromJobCallParts<Ctx> + Send, T5: FromJobCallParts<Ctx> + Send, T6: FromJobCallParts<Ctx> + Send, T7: FromJobCallParts<Ctx> + Send, T8: FromJobCallParts<Ctx> + Send, T9: FromJobCallParts<Ctx> + Send, T10: FromJobCallParts<Ctx> + Send, T11: FromJobCallParts<Ctx> + Send, T12: FromJobCallParts<Ctx> + Send, T13: FromJobCallParts<Ctx> + Send, T14: FromJobCallParts<Ctx> + Send, T15: FromJobCallParts<Ctx> + Send, T16: FromJobCall<Ctx, M> + Send,

Source§

type Future = Pin<Box<dyn Future<Output = Option<JobResult>> + Send>>

Source§

impl<F, Fut, Res, Ctx> Job<((),), Ctx> for F
where F: FnOnce() -> Fut + Clone + Send + Sync + 'static, Fut: Future<Output = Res> + Send, Res: IntoJobResult,

Source§

type Future = Pin<Box<dyn Future<Output = Option<JobResult>> + Send>>

Source§

impl<L, J, Ctx, T> Job<T, Ctx> for Layered<L, J, T, Ctx>
where L: Layer<JobService<J, T, Ctx>> + Clone + Send + Sync + 'static, <L as Layer<JobService<J, T, Ctx>>>::Service: Service<JobCall> + Clone + Send + 'static, <<L as Layer<JobService<J, T, Ctx>>>::Service as Service<JobCall>>::Response: IntoJobResult, <<L as Layer<JobService<J, T, Ctx>>>::Service as Service<JobCall>>::Future: Send, J: Job<T, Ctx>, T: 'static, Ctx: 'static,

Source§

impl<T, Ctx> Job<IntoJobResultHandler, Ctx> for T
where T: IntoJobResult + Clone + Send + Sync + 'static,