Embedding & Extension (SPI)
Rift is not only a standalone binary — it is a library you can embed in a Rust process, drive over a stable C-ABI from any language, and extend through service-provider-interface (SPI) traits. This section documents that surface: how to run the server in-process, how to bind its admin and metrics planes to your own addresses, how to plug in custom storage backends, and how to call it through the FFI.
Everything here reflects the code that ships today. If a signature in these pages ever disagrees with the source, the source wins — please file an issue.
When to use which entry point
| You want to… | Use | Page |
|---|---|---|
| Run the full Rift server (imposters + admin API + metrics) inside a Rust host | ServerBuilder | Embeddable Server |
Bind the admin or metrics plane to a chosen (or ephemeral :0) address and learn the bound port | AdminApiServer::bind / bind_metrics_server | Embeddable Server |
| Replace a storage backend (flow-state, request journal, proxy recording, response sequencing) | SPI traits on ImposterManager | Extension Points (SPI) |
| Observe reconciliation events or decorate responses | ImposterEventListener / ResponseDecorator | Extension Points (SPI) |
| Drive Rift from a non-Rust host (JVM, Node, Go, …) | The C-ABI (rift-ffi) | FFI (C-ABI) |
Runtime topology is yours to choose when embedding. The
--runtime per-coreflag (Performance → Runtime Topology) is a property of theriftbinary’s bootstrap — an embedded host runsServerBuilderon whatever Tokio runtime it already owns. To opt into the same per-core listener fan-out from a host, pass your worker runtime handles toServerBuilder::accept_runtimes(...)(orImposterManager::with_accept_runtimes(...)); omit them for the default single-listener topology.
Crate map
| Crate | Role | Exposes |
|---|---|---|
rift-mock-core | The engine library — no CLI, no HTTP server wiring. | ImposterManager and the SPI traits (FlowStoreProvider, ResponseSequencer, RequestJournal, ProxyRecordingStore, ImposterEventListener, ResponseDecorator), behaviors, predicates, scripting. |
rift-http-proxy | The server crate — builds the rift binary and hosts the admin/metrics HTTP layer. | ServerBuilder, RunningServer, AdminApiServer, bind_metrics_server, the single-port gateway, install_default_crypto_provider(). |
rift-ffi | The C-ABI shared library (cdylib) plus an rlib for in-crate tests. | The extern "C" functions (rift_start, rift_serve_admin, …) and the cbindgen header. |
The Node.js package used to live here as
packages/rift-node. It now has its own repository —achird-labs/rift-node— which owns and publishes the npm package; this repository no longer builds or publishes it.
Cargo features
The engines and allocator are feature-gated. Relevant features:
| Feature | Default (rift-http-proxy) | Default (rift-ffi) | Effect |
|---|---|---|---|
redis-backend | on | on | Redis flow-store backend |
javascript | on | on | JavaScript scripting engine (Boa) |
mimalloc | on | never forwarded | mimalloc global allocator (a cdylib must not impose an allocator on its host, so rift-ffi deliberately never enables it) |
jemalloc | off | n/a | Opt-in alternative allocator, kept for the #717 bake-off. If both mimalloc and jemalloc are enabled (as in CI’s --all-features lanes), mimalloc wins — this is resolved by cfg precedence, not an error. mimalloc remains the shipped default. |
quamina-matching | on | on | Quamina-backed body-field candidate dimension. Off ⇒ the dimension compiles to a no-op that never prunes and every body predicate is decided by the full Stage-2 evaluation — matching results are identical either way, only the prefilter speed differs. |
Because
rift-http-proxyandrift-ffitakerift-mock-corewithdefault-features = false, each engine feature above must be explicitly forwarded to reach what actually ships.scripts/verify-feature-propagation.shenforces that in CI, so a feature cannot be default-on for the library and silently absent from the binary — which is what #777 fixed.
A minimal embedding
use rift_http_proxy::{ServerBuilder, Cli, install_default_crypto_provider};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Required before serving any HTTPS imposter — installs the rustls (ring) provider once.
install_default_crypto_provider();
// Run the standard server exactly as the `rift` binary would, from parsed CLI options.
ServerBuilder::from_cli(Cli::parse()).run().await
}
See Embeddable Server for injecting a custom ImposterManager, binding to ephemeral ports, and graceful shutdown.