Does a low-traffic Crystal HTTP::Server app need preview_mt, or is the default fiber scheduler enough?
0 reputation · 12 Jul 2024, 07:02 UTC
0 reputation · 12 Jul 2024, 07:02 UTC
I'm planning a small Crystal service built on the standard library's HTTP::Server. Expected load is low: a handful of concurrent connections at most, with handlers that are almost entirely I/O-bound (waiting on sockets and a database driver). The goal is to pick the simplest deployment that stays responsive without paying for capacity I don't need.
My understanding is that Crystal schedules fibers cooperatively on a single thread by default, and that HTTP::Server runs each connection in its own fiber, so concurrent connections interleave whenever a handler yields on I/O. The alternative is compiling with the preview_mt flag, which the project has historically described as experimental, with thread-safety across the standard library not fully guaranteed. I'm unsure whether that status still holds in current releases, and I don't want to adopt an experimental runtime mode without a concrete reason.
One specific concern: if any handler does non-trivial CPU work (say, JSON serialization of a larger payload), does it stall all other connections for its duration under the default scheduler, and is that the realistic trigger for needing preview_mt at all?
For a handful of concurrent connections that are almost entirely I/O‑bound, the default single‑threaded, cooperative fiber scheduler is the documented, supported choice. preview_mt is still marked experimental and should be avoided unless you have a measurable CPU‑bound workload that blocks all other requests for noticeable time.
Crystal’s runtime schedules fibers cooperatively on a single OS thread. Each HTTP::Server connection runs in its own fiber and yields automatically on I/O operations (socket reads/writes, database driver calls, etc.). As long as a handler performs no long, blocking CPU work, the scheduler interleaves requests and keeps latency low.
preview_mt activates a multithreaded scheduler that can run several fibers in parallel. It is useful only when a handler performs significant CPU work that does not yield. For example, serializing a 1 MB JSON payload can take several milliseconds on a single core; if that happens for many concurrent connections, the single‑threaded scheduler will stall other requests.
--preview_mt and compare.Do you expect JSON serialization or other CPU work to take more than a few milliseconds per request? The answer will influence whether the single‑threaded scheduler is sufficient.
# Build without preview_mt (default)
crystal build src/main.cr
# Build with preview_mt
crystal build src/main.cr --preview_mt
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.