fix(browser): harden daemon runtime lifecycle#543
Open
xiami762 wants to merge 3 commits into
Open
Conversation
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
Harden the
flocks browserdaemon runtime so named sessions are isolated, same-session startup is serialized, IPC endpoints can be authenticated and identified, and cleanup never relies on signalling an unverified PID.The PR also improves CDP discovery and diagnostics, and adds regression coverage for concurrent startup, graceful shutdown, stale artifacts, legacy daemon compatibility, and browser profile probing.
Key Changes
Runtime paths and session isolation
BrowserRuntimePathsas the single resolver for browser runtime artifacts.FLOCKS_ROOTenvironment variable; the default remains~/.flocks/browser/.bu.*and isolate namedBU_NAMEsessions onbu-<name>.*.IPC and daemon identity
pingresponse containing the session name, PID, instance ID, protocol version, and browser kind.Lifecycle and concurrent startup
CDP connection and diagnostics
DevToolsActivePortcandidates through/json/versionwhen available; if Chrome returns an HTTP error, fall back to the WebSocket path from the profile record so the daemon's real CDP handshake can proceed without a 30-second setup stall.flocks browser --doctorperform a real CDPBrowser.getVersionhandshake for explicitBU_CDP_URLandBU_CDP_WStargets.about:blanktargets out of the managed-tab registry, and ensurenew_tab()creates a distinct managed tab.Documentation
FLOCKS_ROOT, named-session artifact names, persistent lock files, and safe--reloadcleanup.Impact Scope
BU_NAMEnow coordinate through the session lock.--reload, setup, service shutdown, diagnostics, logs, and runtime artifact names use the hardened lifecycle behavior. Named sessions no longer share the default daemon artifacts.bu.*filenames. Legacy Windows integer port files remain readable, and a confirmed legacy default daemon can still be stopped gracefully.BU_NAME,FLOCKS_ROOT,BU_CDP_URL, andBU_CDP_WSsettings are honored more consistently.--doctorperforms an explicit CDP handshake when a remote endpoint is configured.Business Logic to Review
flocks/browser/_ipc.py: lock ownership, atomic endpoint publication, Windows token injection, strict ping validation, and the invariant that endpoint cleanup requires the matching acquired lock.flocks/browser/lifecycle.py: graceful shutdown ordering, preservation of invalid or locked endpoints, legacy-default confirmation, and per-session failure collection.flocks/browser/admin.py::ensure_daemon: lock-busy retry behavior. After exit code 75, the caller waits for the session lock, releases its probe lock, and respawns within the original deadline; another contender may win the race, in which case the loop continues waiting for the published endpoint.flocks/browser/daemon.py: the daemon acquires the session lock before publishing PID/endpoint state, holds it through CDP cleanup, and removes only its own PID record.Why This Approach
An on-disk PID is not sufficient process identity because it may be stale or reused. Combining a lifetime session lock with a protocol-level identity makes startup serialization and cleanup deterministic without terminating an unrelated process.
The design keeps existing environment-based session selection and default runtime filenames, while adding isolation and authentication only where required. Legacy support is deliberately narrow so backward compatibility does not weaken the new cleanup invariants.
Test Plan
uv run pytest -q tests/browser(106 passed)uv run pytest -q tests/cli/test_service_manager.py::test_stop_all_uses_supervisor_control_api tests/cli/test_service_manager.py::test_stop_all_reports_when_supervisor_is_down tests/cli/test_service_manager.py::test_stop_all_uses_legacy_runtime_ports_for_orphan_cleanupuv run ruff check flocks/browser tests/browseruv run ruff format --checkfor the changed Python files, excluding the pre-existing unformattedtests/browser/test_helpers.pygit diff --checkRegression coverage includes named runtime paths, malformed endpoint records, authenticated Windows requests, private POSIX sockets, same-session lock contention, lock-busy startup takeover, strict identity validation, graceful shutdown refusal, legacy compatibility, stale artifact cleanup, CDP client shutdown, OS-specific profiles,
DevToolsActivePortfallback after metadata HTTP 404, and real CDP probing.Compatibility, Migration & Rollback
BU_NAMEreceive isolated artifacts automatically..lockfiles are harmless advisory-lock artifacts and should not be deleted manually.Out of Scope
--nameoption;BU_NAMEremains the session selector.