Skip to main content

StepFuture

Type Alias StepFuture 

Source
pub type StepFuture<'a> = Pin<Box<dyn Future<Output = Result<(), Error>> + 'a>>;
Expand description

A future returned by a migration step — boxed so Migration stays object-safe (the runner holds Box<dyn Migration<X>>).

§This future is not Send, and cannot be made so on stable

Everywhere else in this crate Send-ness leaks: repo:: and Query return unboxed futures, so theirs are Send exactly when the concrete executor’s are — no bound declared, and both a multi-threaded server and a single-threaded Worker are served by one implementation.

Boxing behind dyn destroys that, because Box<dyn Future> is !Send whatever was boxed. The bound would have to be written here — and it cannot be satisfied: CreateTable implements Migration<X> for every X: Executor, so its up would have to produce a Send future for every executor, and whether X::execute’s future is Send is unknowable in a generic context. Expressing it needs return-type notation (X: Executor<execute(..): Send>), still unstable.

So Migrator::run is the one API here that cannot be awaited inside a tokio::spawned task. Two ways round it, both fine in practice:

  • Run migrations outside a spawned task — at boot, on the main future. This is what most applications do anyway.
  • Render synchronously and execute the strings yourself. schema::schema_ddl and ddl::Migration::render are ordinary synchronous functions returning Vec<String>, so a caller that needs a Send future can render first and then await plain execute calls — no boxed future anywhere.

tests/send_futures.rs asserts the Send property for everything that can hold it, and documents this exception.

Aliased Type§

pub struct StepFuture<'a> { /* private fields */ }