fix(mine): detect concurrent palace holder, exit non-zero with clear error (#1264) - #1349
fix(mine): detect concurrent palace holder, exit non-zero with clear error (#1264)#1349adv3nt3 wants to merge 1 commit into
Conversation
|
Heads up: the macOS CI failure is unrelated to this PR.
This PR adds no network calls — Could a maintainer re-run the failed macOS job? I can't trigger it from my fork without admin rights. If you'd prefer I push a no-op commit to retrigger CI, happy to do that — let me know. |
…error (MemPalace#1264) When `mempalace.mcp_server` (or any other writer) holds chroma.sqlite3 open, `mempalace mine` would print only the auto-defaults stderr warning and exit with no diagnostic visible — the chroma open hit lock contention or a Rust-binding SIGSEGV under chromadb 1.5.x's concurrent-writer path, and stdout buffering ate the banner that would have explained things. Adds a pre-flight `detect_palace_holder()` to `palace.py` that uses `lsof` on POSIX to find a non-self process holding the palace's chroma.sqlite3, with a coarse `ps`-based classification (mcp_server vs. mine vs. raw command name). `mine()` checks before any other output and exits 1 with a one-line stderr error including palace path, holder PID, process kind, and a suggested next step. The existing `MineAlreadyRunning` catch now also exits 1 (was: clean exit 0 with "exiting cleanly" wording, which was misleading per the issue). Windows and hosts without `lsof` degrade silently to None — pre-flight becomes a no-op and the existing behavior is preserved. Dry-run skips the pre-flight (no chroma open). Complementary to PR MemPalace#1162's structural fix at the ChromaCollection lock layer.
90bd2f4 to
c48f25a
Compare
|
Rebased onto develop to resolve the merge conflict (single-line import collision in |
|
Closing — superseded by #1413 (merged), which solves #1264 with a cleaner approach:
Thanks @igorls for the better fix. Leaving this PR closed; the test ideas from |
Fixes #1264.
What does this PR do?
Closes the operator-visible silent-exit gap when
mempalace mineis run while another writer (typicallymempalace.mcp_server) holds the palace'schroma.sqlite3open.Today,
minewould:load_config.The result was the 200-byte log described in #1264.
This PR adds a pre-flight detection that runs before any other output and bails with a clear message + non-zero exit when a holder is found. It's complementary to #1162's structural fix at the
ChromaCollectionlock layer — once that lands, the lock-layer raise reaches the same loudMineAlreadyRunninghandler instead of disappearing.Changes
mempalace/palace.py— new helperdetect_palace_holder(palace_path) -> Optional[dict]lsof -Fpcnto find the first non-self process holding<palace>/chroma.sqlite3_classify_palace_holder(pid, command)inspects full argv viapsto classify the holder asmempalace.mcp_server,mempalace mine, or the raw command name as fallbackNoneon Windows or whenlsofis unavailable, missing, or times out — graceful degrade preserves prior behavior on platforms we can't probemempalace/miner.py— wire pre-flight intomine()load_config, the banner, andget_collection. The auto-defaults warning can no longer leak through as the only line of an operator's log.sys.exit(1).MineAlreadyRunning: wasreturn(clean exit 0 with"exiting cleanly"wording, which the issue called out as misleading); nowsys.exit(1)with a clearcannot startmessage.tests/test_detect_palace_holder.py— new test file13 tests covering:
chroma.sqlite3→ no detection attemptlsofunavailable / timeout / non-zero exit → gracefulNonepsNone(monkeypatch.setattr(sys, "platform", "win32"))mine()exits 1 with clear stderr when a holder is detected, without the auto-defaults warning leakingmine()exits 1 with clear stderr onMineAlreadyRunningmine()proceeds normally when no holder is reportedHow to test
Verified locally on macOS 26.4 (Apple Silicon, Python 3.14):
lsofcorrectly identifies the holding PID, the message reaches stderr before any other output, and exit code is 1.Scope
mineentry point.mempalace sweep— same writer entry-point class; the issue mentions it as plausible-same-shape but unverified. Suggest a follow-up PR mirroring this fix incmd_sweeponce we confirm the same silent-exit behavior there.Behavior change to flag
The
MineAlreadyRunninghandler now exits 1 instead of 0. The previous behavior was documented as "exiting cleanly", but per the issue's recommendation a non-zero exit makes nohup / shell wrappers / hooks see a useful signal.mempalace.hooks_cli._spawn_minedoes not check the subprocess exit code, so the hook path is unaffected. If any caller relied on exit 0 from "another mine running", they should be updated to expect 1.Checklist
pytest tests/ -v— 1502 passed, 1 skipped)ruff check .— All checks passed)subprocessandsysfrom stdlib)Refs:
mine: silent exit when concurrent writer holds chroma lock; should detect livemcp_serverand back off with clear error #1264 (this fix)mine_palace_lockfor mine-vs-mine)