Add daemon server for persistent RBS environment#2080
Open
rhiroe wants to merge 2 commits intosoutaro:masterfrom
Open
Add daemon server for persistent RBS environment#2080rhiroe wants to merge 2 commits intosoutaro:masterfrom
rhiroe wants to merge 2 commits intosoutaro:masterfrom
Conversation
6ffa5c3 to
f75557a
Compare
Implement a daemon mode that keeps Steep's LSP Server (Master + Workers) running persistently so that the expensive RBS environment loading is performed only once. Subsequent `steep check` invocations connect to the daemon via Unix socket and skip the startup cost. - `steep server start/stop/restart/status` subcommands - `steep check --[no-]daemon` option (daemon enabled by default) - Background file watcher for automatic RBS re-warming on signature changes - Fallback to standard mode when daemon is not available
f75557a to
35f4532
Compare
Contributor
|
I wonder if the RBS environment daemon and the language server can be on the same server. |
Author
|
For this PR, I'll reimplement the daemon's external protocol to use LSP instead of the current custom JSON protocol. Regarding full integration of the daemon with the language server (sharing a single
Does this sound reasonable? |
Replace the custom line-delimited JSON protocol between the daemon server and steep check client with standard LSP JSON-RPC, matching the protocol already used internally between Master and Workers.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Introduces a daemon mode for
steep checkthat keeps the LSP server (Master + Workers) running persistently in the background, eliminating the expensive RBS environment loading on every invocation.steep server start|stop|restart|statussubcommands to manage the daemon lifecyclesteep checkautomatically connects to the daemon when available (opt out with--no-daemon)listengem) detects.rb/.rbschanges and notifies the server;.rbschanges additionally trigger pre-warming of the type checkerMotivation
Every
steep checkinvocation currently spawns worker processes that each independently load the full RBS environment (gem signatures, stdlib, project signatures). This is the single largest bottleneck — on the Steep codebase itself, it accounts for most of the ~40s wall-clock time and ~235s cumulative CPU time across workers.The daemon eliminates this by loading the RBS environment once and reusing it across checks.
Benchmark results
Measured on the Steep codebase itself (
steep check --severity-level=error, Ruby 3.4.8, Linux aarch64, 10 CPU cores / 9 workers).Full project check
--no-daemon)Single-file check (
lib/steep/subtyping/check.rb, 1112 lines)--no-daemon)Performance characteristics
The daemon's speedup comes from eliminating the fixed overhead (RBS environment loading + worker process startup) that dominates every non-daemon invocation. How much it helps depends on the ratio of fixed overhead to actual type-checking work:
The fewer files you check, the larger the daemon's relative speedup:
This means the daemon is most impactful for:
The daemon is least impactful (but still faster) when:
RBS change impact
When RBS signatures are modified, the daemon detects the change and re-warms incrementally (full project check):
Even immediately after an RBS change, the daemon is still 1.7x faster than non-daemon.
No regression in non-daemon mode
--no-daemon)Both are well within natural measurement variance (±3–4s between runs).
How it works
Without daemon (existing behavior):
With daemon:
CLI changes
steep server start— Start the daemon (double-fork, returns immediately)steep server stop— Stop the daemon (SIGTERM with graceful fallback to SIGKILL)steep server restart— Stop + startsteep server status— Show daemon status (Ready/Warming up/Starting/Not running)steep check --[no-]daemon— Enable/disable daemon auto-detection (default: enabled)Note: The daemon loads the Steepfile at startup. If the Steepfile is modified (e.g., adding targets, changing libraries), run
steep server restartto pick up the changes.