Skip to content

fix: serialize daemon startup on POSIX - #527

Open
tabtablabs-dev wants to merge 1 commit into
browser-use:mainfrom
tabtablabs-dev:codex/browser-harness-daemon-start-lock
Open

tabtablabs-dev wants to merge 1 commit into
browser-use:mainfrom
tabtablabs-dev:codex/browser-harness-daemon-start-lock

Conversation

@tabtablabs-dev

@tabtablabs-dev tabtablabs-dev commented Jul 14, 2026

Copy link
Copy Markdown

Summary

  • serialize ensure_daemon() by daemon name with a POSIX flock
  • prevent concurrent cold-start callers from spawning duplicate detached daemons
  • add a regression test covering eight concurrent callers

Reproduction

On macOS, concurrent harness calls left 211 python -m browser_harness.daemon processes adopted by PID 1. ensure_daemon() checked daemon state before spawning without a cross-process startup lock, so several callers could observe the same missing endpoint and spawn together.

The regression test fails on current main with multiple spawns and passes with this change.

Verification

  • uv run --with pytest pytest -q
  • 115 passed
  • installed the updated editable tool locally
  • no orphaned daemons remain after cleanup

Windows behavior is unchanged.


Summary by cubic

Serialize daemon startup on POSIX to prevent duplicate spawns when multiple callers invoke ensure_daemon(). Adds a per-daemon file lock and a regression test; Windows behavior is unchanged.

  • Bug Fixes
    • Added _daemon_startup_lock using POSIX flock on a per-daemon .lock file.
    • Wrapped ensure_daemon with the lock and split out _ensure_daemon_unlocked.
    • Added a regression test that runs 8 concurrent callers and asserts a single spawn.

Written for commit 092f3d6. Summary will update on new commits.

Review in cubic

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="tests/unit/test_admin.py">

<violation number="1" location="tests/unit/test_admin.py:46">
P2: The lock file created by `_daemon_startup_lock` lands in the real system runtime directory instead of `tmp_path`. If the runtime dir is unwritable (sandboxed CI, read-only home), the test fails with a permission error. The lock file also persists after the test and could pollute parallel test runs. Mock `pid_path` (or the whole `_daemon_startup_lock`) so the lock file is scoped to `tmp_path` alongside `log_path`.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread tests/unit/test_admin.py

monkeypatch.setattr(admin, "daemon_alive", daemon_alive)
monkeypatch.setattr(admin.ipc, "connect", lambda *_args, **_kwargs: (FakeSocket(b'{"result":{}}\n'), None))
monkeypatch.setattr(admin.ipc, "log_path", lambda _name: tmp_path / "daemon.log")

@cubic-dev-ai cubic-dev-ai Bot Jul 14, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The lock file created by _daemon_startup_lock lands in the real system runtime directory instead of tmp_path. If the runtime dir is unwritable (sandboxed CI, read-only home), the test fails with a permission error. The lock file also persists after the test and could pollute parallel test runs. Mock pid_path (or the whole _daemon_startup_lock) so the lock file is scoped to tmp_path alongside log_path.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At tests/unit/test_admin.py, line 46:

<comment>The lock file created by `_daemon_startup_lock` lands in the real system runtime directory instead of `tmp_path`. If the runtime dir is unwritable (sandboxed CI, read-only home), the test fails with a permission error. The lock file also persists after the test and could pollute parallel test runs. Mock `pid_path` (or the whole `_daemon_startup_lock`) so the lock file is scoped to `tmp_path` alongside `log_path`.</comment>

<file context>
@@ -20,6 +23,35 @@ def close(self):
+
+    monkeypatch.setattr(admin, "daemon_alive", daemon_alive)
+    monkeypatch.setattr(admin.ipc, "connect", lambda *_args, **_kwargs: (FakeSocket(b'{"result":{}}\n'), None))
+    monkeypatch.setattr(admin.ipc, "log_path", lambda _name: tmp_path / "daemon.log")
+    monkeypatch.setattr("subprocess.Popen", FakeProcess)
+
</file context>
Fix with cubic

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