Skip to content

feat: daemon mode so models load once across CLI invocations - #3

Merged
comppaz merged 1 commit into
mainfrom
feat/daemon-mode
Apr 27, 2026
Merged

feat: daemon mode so models load once across CLI invocations#3
comppaz merged 1 commit into
mainfrom
feat/daemon-mode

Conversation

@comppaz

@comppaz comppaz commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Auto-spawned noirdoc-daemon keeps spaCy + GLiNER models in memory, eliminating the ~10 s cold-start per noirdoc redact (cold 2.97 s → warm 0.07 s, ~40×).
  • AF_UNIX socket + JSON-lines protocol under ~/.noirdoc/, pydantic-validated envelope (hello, redact, status, shutdown).
  • Single asyncio.Lock enforces FIFO serialization; idle shutdown after 10 min (configurable via NOIRDOC_DAEMON_IDLE_SECONDS).
  • Version handshake respawns mismatched daemons; any daemon failure falls back transparently to in-process Redactor.
  • Adds noirdoc daemon {status,stop,restart,logs} and a --no-daemon / NOIRDOC_NO_DAEMON opt-out for noirdoc redact.

Test plan

  • pytest tests/daemon/ — 28/28 passing (protocol round-trips, spawn / stale-socket cleanup, serial queue + queue-depth, version handshake, fallback)
  • Manual cold/warm benchmark: 2.97 s → 0.07 s on identical input
  • mypy + ruff clean (pre-commit hooks pass)
  • Manual smoke on a fresh checkout: noirdoc daemon status → not running, two noirdoc redact calls back-to-back, then idle-shutdown after 10 min
  • Crash test: kill -9 mid-request, confirm fallback warning + completion

Adds an auto-spawned `noirdoc-daemon` that holds the spaCy + GLiNER models
in memory, eliminating the ~10s cold-start per `noirdoc redact` call.

- AF_UNIX socket + JSON-lines protocol under `~/.noirdoc/`
- Pydantic-validated envelope (`hello`, `redact`, `status`, `shutdown`)
- Single asyncio lock for FIFO serialization; queue depth tracked
- Idle shutdown after 10 min (configurable via NOIRDOC_DAEMON_IDLE_SECONDS)
- Version handshake: CLI shuts down + respawns mismatched daemon
- Transparent fallback to in-process Redactor on any daemon failure
- New `noirdoc daemon {status,stop,restart,logs}` subcommands
- `--no-daemon` / `NOIRDOC_NO_DAEMON` opt-out for `noirdoc redact`

Cold-path benchmark: 2.97s -> 0.07s warm (~40x). Models cached in the
daemon; namespaces re-read from disk per request to avoid coherence bugs.
@comppaz
comppaz merged commit ed54e7f into main Apr 27, 2026
3 checks passed
@comppaz
comppaz deleted the feat/daemon-mode branch April 27, 2026 08:48
comppaz added a commit that referenced this pull request Apr 27, 2026
The v0.1.1 tag shipped without a corresponding changelog section, so the
daemon (PR #3) was undocumented and `ns summary` (PR #2) was still parked
under [Unreleased]. Backfill the section now so the GitHub release link
(which dereferences to CHANGELOG.md) and future readers see what 0.1.1
actually contained. Documentation-only; no code change, no re-tag.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant