Skip to content

meta-exporter: CDP plumbing has no timeout — an endpoint that accepts but never answers hangs the exporter forever and writes no failure document #2175

Closed

Description

@dezren39

Summary

pm-stack/meta-exporter/meta-quota-export.mjs has no timeout anywhere in its CDP plumbing, so a browser debug endpoint that accepts the connection but never answers hangs the exporter forever instead of producing one of its designed failure documents:

  • httpJson (meta-quota-export.mjs, CDP plumbing section) — await fetch(url) with no AbortSignal; used for ${cdpBase}/json/list in both run() and fetchPaygBalance().
  • connectWs — the promise resolves only on ws.onopen and rejects only on ws.onerror; if the socket opens but the page never answers, send()'s per-call promise is stored in pending and never settled (no onclose handler rejects pending calls), so evaluate() (which awaits client.send("Runtime.evaluate", …)) hangs indefinitely.
  • The in-page fetch calls in fetchQuotaPayloads likewise carry no timeout, though Runtime.evaluate with awaitPromise: true means a hung in-page fetch also never returns.

The module's own header documents the contract this breaks: every failure mode is supposed to write a failure document (cdp-unavailable exit 4, fetch-failed exit 7, …) so a failed tick "can never be mistaken for a reading", and consumers derive laptop-unreachable only from the age of latest.json. A hang produces no document at all — under the shipped systemd units the only backstop is meta-quota-export.service's TimeoutStartSec=120, which SIGTERMs the process: still no failure document, no exit-code semantics, and the stale latest.json is then misread downstream as the laptop being unreachable rather than the browser/CDP being wedged.

Evidence (verified this run on main c58507a3)

  • Grep: no timeout / AbortSignal / setTimeout anywhere in meta-quota-export.mjs.
  • connectWs: pending promises are resolved/rejected only in ws.onmessage; there is no ws.onclose handler at all, so a socket that closes mid-Runtime.evaluate also leaves evaluate() pending forever.
  • Sandbox probe: started a TCP server on 127.0.0.1:19299 that accepts connections and never replies, then ran the shipped exporter against it:
    node meta-quota-export.mjs --cdp-port 19299 --out-dir /tmp/probe-metaexp/out under timeout 8 → exit 124 (killed by timeout; the exporter never returned), and the out-dir contained zero files — no latest.json failure document, no history.jsonl entry.
  • Control behaviour by contrast: an unreachable port (connection refused) does produce the designed cdp-unavailable failure document via the catch in run() — it is specifically the accepts-but-never-answers case that has no path to any outcome.

Why it matters

This exporter is the Meta pool's only quota feed (code#1301, epic #1149); the aggregator's pool decisions ingest its file export every 15 minutes. A wedged browser page or CDP endpoint currently turns into up to 120 s of systemd kill-wait per tick, zero diagnostics in the export stream (the failure taxonomy exists precisely to name this state), and a downstream signal that points operators at the laptop's reachability instead of the browser session.

Acceptance criteria

  • Every CDP HTTP fetch (/json/list) carries a bounded timeout (e.g. AbortSignal.timeout(...)) that surfaces as the existing cdp-unavailable failure document + exit 4.
  • WebSocket send() calls carry a bounded deadline, and ws.onclose/onerror rejects all pending promises, so a hung or closed socket surfaces as fetch-failed (exit 7) instead of hanging.
  • The in-page quota fetch is bounded (directly, or transitively via the Runtime.evaluate deadline above).
  • A test (the file already has meta-quota-export.test.mjs) covers the accepts-but-never-answers endpoint: the run terminates with a failure document well inside the systemd 120 s budget.
  • Healthy-path behaviour unchanged: success document shape, failure taxonomy, and exit codes all as documented in the module header.

Dedup / distinctness

Activity

  1. developing-today commented on Oct 29, 2026

    @developing-today
    Contributor
  2. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    priority/normalOrdinary priority (the default)
    queue/queuedHas a queued task in the Supabase agent queue
    source/creatorFiled by the new-issue-creator job
    task/triageQueue packet kind: verify, reproduce, and route this item
    app/pm-stackpm-stack (Pad/Grist) in developing-today/code
    effort/sSmall: expected under 2 hours of work
    on Oct 29, 2026
  3. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator job (new-issue-creator-code-b)
    • Session / ID: cron new-issue-creator-code-b, run 2026-10-29 02:20 CDT
    • Found via: filed this run
    • Task: Triage the meta-exporter's timeout-less CDP plumbing (pm-stack/meta-exporter/meta-quota-export.mjs httpJson/connectWs/evaluate): pin per-call deadline values that land well inside the systemd TimeoutStartSec=120 budget and map to the existing cdp-unavailable/fetch-failed failure documents, then route a small_fix packet.
    • Expectation: effort/s; done = /json/list fetches bounded, WS send() deadline + onclose rejects pending, accepts-but-never-answers test writes a failure document, healthy path unchanged.
    • Links: evidence file hidden_files/issue-code-metaexporter-cdp-timeout-body.md (sandbox probe: hang server on 127.0.0.1:19299, exporter killed at 8s exit 124, zero output files, main c58507a)
  4. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 1, 2026
  5. 34 remaining items

  6. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    PR opened: Task 5204 implementation is in PR #4138.

    • Agent: repo-worker-code (OpenChamber scheduled lane)
    • Scope: 10s HTTP fetch/body deadline, 10s WebSocket-open deadline, 30s CDP command/evaluate deadline; close/error rejects all pending calls.
    • Verification: targeted test suite passes 21/21 after merging current origin/main; output-document and exit mapping regressions are covered.
    • CI: GitHub test check is pending; observing for up to five minutes, then will park if needed.
  7. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    Parked: Task 5204 is parked for 20 minutes while PR #4138 checks run.

    • Agent: repo-worker-code (OpenChamber scheduled lane)
    • Fresh CI state: PR fix(meta-exporter): bound CDP waits and persist failures #4138 is OPEN; required test workflow is still queued/pending. CodeRabbit skipped.
    • Local verification: targeted Node suite passed 21/21 after merging current origin/main.
    • Resume: re-read PR/check state; merge only after required checks pass and the diff remains in scope.
  8. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    queue/claimedQueue worker lifecycle state
    and removed
    queue/claimedQueue worker lifecycle state
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    work/assignedQueue worker lifecycle state
    on Nov 2, 2026
  9. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    agent-note:v1 — task 5204 done

    PR #4138 merged (merge commit 56e66c9): bounded CDP waits in pm-stack/meta-exporter (fetch/WebSocket/evaluate deadlines, pending-request rejection on close/error) with failure documents preserved; diff is exactly the two in-scope files.

    Verification: node --test pm-stack/meta-exporter/meta-quota-export.test.mjs on the laptop worktree at PR head 3494110 — 21/21 pass (re-run fresh this shift). Codex review on the PR head completed with no findings. GitHub Actions test check was still queued in the Actions backlog (>50 min) at merge time; merged under Drew's standing merge authority with laptop verification, same as prior fleet merges during this backlog. Closing #2175 as fixed.

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

Metadata

Metadata

Assignees

Labels

app/pm-stackpm-stack (Pad/Grist) in developing-today/codeeffort/sSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)source/creatorFiled by the new-issue-creator jobtask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions