Skip to content

deploy: PLAY 2 fails at 'Browser | Wait for service to be ready' — autobot-browser-worker has no unit file and :3000 is held by Grafana on loopback; last blocker after #12883 #12912

Closed

Description

@mrveiss

Summary

With #12871 and #12883 fixed, PLAY 2 now runs nearly to completion — backend .env regen, migrations, AI-stack, frontend and NPU all succeed (ok=108 changed=32). It then fails on the last component:

TASK [[PLAY 2] Browser | Restart service] **************************************
changed: [00-SLM-Manager]

TASK [[PLAY 2] Browser | Wait for service to be ready] *************************
fatal: FAILED! => {"changed": false, "elapsed": 61,
                   "msg": "Timeout when waiting for <node-ip>:3000"}

PLAY RECAP
00-SLM-Manager : ok=108  changed=32  unreachable=0  failed=1  skipped=24

The wait can never succeed, for two independent reasons.

Cause 1 — there is no autobot-browser-worker unit

$ systemctl cat autobot-browser-worker
(no output — no unit file)

$ systemctl show autobot-browser-worker -p ActiveState,SubState,Result,NRestarts
ActiveState=inactive
SubState=dead
Result=success
NRestarts=0

$ journalctl -u autobot-browser-worker -n 12
-- No entries --

The service has never started and has no unit on disk. [PLAY 2] Browser | Deploy autobot-browser-worker copies files and Restart service reports changed, but nothing is left listening. (The separate autobot-playwright.service is active — worth confirming which of the two the play intends to manage, because the restart reporting changed while the named unit does not exist suggests it is restarting something else.)

Cause 2 — port 3000 is Grafana, bound to loopback only

$ ss -ltnp | grep :3000
LISTEN 0 4096 127.0.0.1:3000 0.0.0.0:*  users:(("grafana",pid=678,fd=19))

$ curl -o /dev/null -w '%{http_code}' http://127.0.0.1:3000/health   -> 301  (redirects to /grafana/health)
$ curl -o /dev/null -w '%{http_code}' http://<node-ip>:3000/health   -> 000  (nothing listening)

So even if the browser worker started, port 3000 is already taken by Grafana. And the play waits on the node's LAN address, while Grafana binds 127.0.0.1 only — so the probe fails regardless of which service is meant to answer.

Impact

Proposed fix

  1. Establish which unit owns browser automation — autobot-browser-worker or autobot-playwright — and make the play deploy, restart and probe that one. A Restart service task reporting changed for a unit that does not exist is a silent no-op worth fixing on its own.
  2. Resolve the port collision: move the browser worker off 3000, or move Grafana. Two services configured for the same port on one host cannot both be right.
  3. Probe the address the service actually binds. If it is loopback-only by design, waiting on the LAN address will always time out.
  4. Consider making the wait non-fatal (or ignore_errors with a warning) so one unready optional worker does not fail an otherwise complete update — the other 108 tasks succeeded.

Related

Verification

sudo tail -40 /var/log/autobot/self-update-ansible.log | grep -A4 "Browser | Wait"
systemctl cat autobot-browser-worker ; systemctl is-active autobot-playwright
sudo ss -ltnp | grep :3000

Activity

  1. mrveiss commented on Jul 29, 2026

    @mrveiss
    OwnerAuthor

    This is blocked by #12959 as well as by its own two causes — worth recording before anyone writes the fix.

    Checked the role that owns the browser component:

    roles/browser/templates/
      playwright.service.j2
      autobot-browser-worker.env.j2      <- env file exists
      vnc.service.j2
      role.json.j2
    

    There is no autobot-browser-worker.service.j2. So the missing unit file is not deployment drift — the template does not exist in the repo either, which matches this issue's finding on the host.

    The second layer is the problem for whoever fixes it. Per #12959, update-all-nodes.yml never applies roles/browser (it appears in PR #12960's report as NEVER applied). So adding the unit template here produces a fix that is correct in the repo and cannot reach a host through code-sync / self-update — the same trap that left #12886 closed while TTS still 404s, and #12907 merged while both credential defects stay live.

    Practical consequence: this issue needs both halves to be verifiable —

    1. add the missing autobot-browser-worker.service.j2 (and resolve the :3000 conflict with Grafana on loopback), and
    2. CRITICAL(deploy): Update-All uses inline tasks and applies only backend/env_only — every fix landing in an Ansible role is inert on hosts (#12777 faulthandler, #12907 consolidation, #12886 TTS all merged but never delivered) #12959's conversion, so roles/browser is actually applied.

    Fixing only (1) will look done, pass review, close — and PLAY 2 will fail at the identical task on the next run, which is exactly the outcome this issue already reports as "unchanged".

    Confirmed on the host just now: no autobot-browser-worker unit is present in systemctl list-unit-files.

  2. github-actions commented on Jul 31, 2026

    @github-actions
    Contributor

    PR #13150 (merged to Dev_new_gui) references this issue with a close keyword.

    fix(deploy): wait on the port the browser worker binds, and deliver the backend unit (#12912, #12777)

    If this issue is fully resolved, close it manually. If work remains, no action is needed.

  3. mrveiss commented on Aug 1, 2026

    @mrveiss
    OwnerAuthor

    Audit note — repo fix verified, live acceptance still outstanding

    Repo-side, PR #13150 (e489b51dc) addresses causes 1–3 and this was verified on the current tip:

    • Unit identity — the restart now targets autobot-playwright rather than the nonexistent autobot-browser-worker. playwright.service.j2 confirms WorkingDirectory=/opt/autobot/autobot-browser-worker + ExecStart=.../playwright-server.js, so that is the correct unit for the deployed files.
    • Port — the wait is now port: "{{ playwright_port | default(9001) }}", and roles/browser/defaults/main.yml:20 confirms playwright_port: 9001.
    • Cause 4 (making the wait non-fatal) was advisory and not done.

    Why this stays open: PR #13150's own body states that acceptance is host-side and unproven until it merges, and commits to reporting the outcome either way. That report was never posted — the last activity here is the merge note. The issue cannot be discharged by static analysis.

    One residual repo gap found during the audit, worth recording: update-all-nodes.yml renders roles/backend (env_only, unit_only) and roles/tts-worker (code_only), but never renders roles/browser's playwright.service.j2. So the play restarts a unit it does not deliver. If a host's autobot-playwright unit is stale or absent, this play cannot repair it — the same class of defect as #12777, and inside the scope of still-open #12959 ("every fix landing in an Ansible role is inert on hosts").

  4. added this to the v0.9.0 milestone on Sep 12, 2026
  5. mrveiss commented on Sep 12, 2026

    @mrveiss
    OwnerAuthor

    Closing — fully delivered; never auto-closed because Dev_new_gui wasn't GitHub's configured default branch at merge time.

    Verified against origin/main:

    • Port fix: update-all-nodes.yml:1464-1471 waits on {{ playwright_port | default(9001) }}, not hardcoded 3000.
    • Fallback matches role default: roles/browser/defaults/main.yml:20 playwright_port: 9001.
    • Correct unit targeted: update-all-nodes.yml:1449 restarts autobot-playwright, not the nonexistent autobot-browser-worker.
    • Mutation-guard test: tests/test_updater_browser_port_and_backend_unit.py.

    Delivered by merged PR #13150.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions