Cameleeringsimoom

simoom / Use cases / Integration engines

Integration engines and API hosts

The HTTP engine inside an integration platform

An integration engine takes webhooks all day, serves REST and MCP endpoints, streams responses, and some of its calls block on a database or a slow partner system. simoom was built for exactly this host: Cameleer, which runs Apache Camel-style routes in Rust. Fast work stays on the loop; slow work goes to a bounded pool or to the host's own threads.

22% morestatus requests per second than Cameleer's old server at 64 clients, same droplet; campaign 4
33% lessCPU per request at 50,000 req/s: 23.4 µs against 35.2 µs; campaign 4
5.9x lessmemory per idle connection with 10,000 open: 575 B against 3,363 B; campaign 4
4,925 req/swith a 100 ms blocking handler and 500 clients, 0 errors; on a workstation, level with the server it replaced

Answer from the host's own threads

An integration engine already has workers that decide when a reply is ready. simoom hands the service a Responder that can answer from any thread. This is how Cameleer embeds it.

use simoom::{Outcome, Reply, Request, Response, Server};

let server = Server::builder()
    .listen("127.0.0.1:8080")
    .service(|req: &mut Request<'_>, reply: Reply<'_>| -> Outcome {
        let owned = req.to_owned_request();
        let responder = reply.defer();
        std::thread::spawn(move || {
            responder.send(Response::text(format!("done: {}", owned.path_str())));
        });
        Outcome::Done
    })
    .start()
    .unwrap();

Slow calls that don't pile up

Without a host pool, slow work goes to simoom's own offload pool. It is bounded: when it is over capacity, the client gets a fast 503 with Retry-After instead of waiting in a queue that grows without end.

use simoom::{blocking, OwnedRequest, Response, Router};

let router = Router::new().get("/report", blocking(|req: OwnedRequest| {
    // runs on an offload worker, never on a loop thread
    Response::text(format!("report for {}", req.path_str()))
}));

Safety nets

  • Admission to the pool uses CoDel: a fast 503 instead of an unbounded queue.
  • A stall watchdog moves a route whose inline handler turns out slow to the offload pool, and back once it is fast again.
  • A panic in a handler becomes a 500, not a crash.

Measured

  • On a workstation, a handler that blocks for 100 ms with 500 clients: 4,925 req/s with 0 errors, the same as the server it replaced (4,925), which gave each connection a thread.
  • Server CPU per request at a fixed 50,000 req/s: 23.4 µs against 35.2 µs for Cameleer's old server on the same droplet (campaign 4, 2026-11-12).

Guide: slow work. Streaming bodies and server-sent events for long responses: streaming.

The crossing: against the server it replaced

On a workstation (WSL2), server on 4 CPUs, 64 connections, closed loop, both servers returning the same 13-byte answer, 2026-11-09.

measuresimoomcameleer-http
throughput293,000–311,000 req/s172,000–173,000 req/s
p99 latency0.32–0.44 ms0.87–0.91 ms
server CPU per requestabout 13 µsabout 23 µs
memory with 1,000 idle connections2.7 MB7.7 MB
idle memory with TLS1,360 KB1,317 KB

The last row is a loss: 3.3% more idle memory with TLS. In benchmark campaign 4 (2026-11-12, cloud droplets), against the same server on the same droplet, simoom answered 22% more status requests at 64 clients and started 1.9x faster (0.90 ms against 1.74 ms); the old server handled 9% more new connections per second and used less memory at rest (1,146 KB against 1,844 KB). More in the benchmarks and the Cameleering ledger. See Cameleer itself at cameleer.ing.

Common questions

Which integration engine uses simoom?

Cameleer, an independent Rust implementation in the style of Apache Camel, uses simoom as its HTTP engine. simoom was built to replace Cameleer's thread-per-connection server.

How do I answer an HTTP request from another thread in Rust?

Call reply.defer() in the service to get a Responder, move it to any thread, and call send with the response when it is ready. Return Outcome::Done from the service.

What happens when the server is overloaded with slow requests?

The offload pool is bounded and uses CoDel admission. When it is over capacity, the client gets a fast 503 with Retry-After instead of waiting in an unbounded queue.

Can simoom serve MCP and streaming endpoints?

Yes. It serves routes with streamed bodies (Reply::stream), server-sent events (Reply::sse) and WebSocket, which are what REST and MCP endpoints need. The MCP protocol itself is implemented by the host, such as Cameleer.

Is simoom faster than a thread-per-connection server?

Against Cameleer's old thread-per-connection server on the same cloud droplet in benchmark campaign 4 (2026-11-12), simoom answered 22% more status requests per second at 64 clients and was the only one of the two to keep 99% of answers within 1 ms at 256 clients; it used 33% less CPU per request and 5.9x less memory per idle connection. The old server handled 9% more new connections per second and used less memory at rest (1,146 KB against 1,844 KB for simoom's full server). On a workstation (WSL2), against the same server, simoom served 1.7 to 1.8 times the requests and held 1,000 idle connections in 2.7 MB instead of 7.7 MB.

Build it into your host

Start with the deferred reply and the offload pool, then tune limits for your traffic.