Skip to content

Gmail watcher should honor 429 retry-after and circuit-break per account #643

@Countermarch

Description

@Countermarch

Environment

  • gogcli 0.15.0
  • Trigger path: gog gmail watch serve handling Gmail Pub/Sub push delivery
  • Originally surfaced through OpenClaw 2026.5.22 (a374c3a) supervising the external gog watcher process

Impact

A parked legacy Gmail watcher repeatedly hit Gmail 429 rateLimitExceeded during push handling. The Gmail retry-after timestamp kept moving forward because the handler continued receiving Pub/Sub retries and making Gmail API calls instead of circuit-breaking the affected account.

Evidence

Runtime logs repeatedly showed push-handler failures like:

watch: handle push failed: googleapi: Error 429: User-rate limit exceeded. Retry after <redacted-timestamp>, rateLimitExceeded

Additional observations:

  • The errors were from push handling, not only manual watch start attempts.
  • The caller had already paused the legacy account in the supervising app config.
  • The legacy Pub/Sub subscription was absent locally.
  • gog gmail watch status --account <redacted-legacy-account> still showed a stored server-side Gmail watch expiring May 31, 2026.
  • gog gmail watch stop --account <redacted-legacy-account> --force succeeded and cleared the stale local watch state.

Repository boundary

This was first filed as openclaw/openclaw#86610, but review there found OpenClaw only configures, starts, renews, and supervises the external gog gmail watch serve process. The repeated history.list / messages.get fetches are in the gogcli push handler, so this issue belongs here.

Expected behavior

When Gmail returns 429 with a retry-after value, the watcher should pause Gmail API fetches for that account until after the retry-after time. Pub/Sub push handling should not continue making history.list / messages.get calls on every redelivery while the account is already rate-limited.

Suggested fix

  • Add a per-account 429 circuit breaker in gog gmail watch serve.
  • Persist the retry-after timestamp in watch state.
  • While the circuit is open, return a controlled response and avoid Gmail API calls for that account.
  • Consider a lower-cost metadata-only mode for low-importance watchers.
  • Add an explicit command to pause/stop the server-side watch while keeping local config parked.

Local recovery used

Stopped the stale server-side watch for the parked legacy account and left only the intended workspace watcher active. After recovery, the parked account had no local listener, no legacy Pub/Sub subscription, and no stored gog watch state.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal priority bug or improvement with limited blast radius.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:needs-live-reproClawSweeper needs live local, crabbox, or manual validation to confirm this issue.clawsweeper:queueable-fixClawSweeper marked this issue as an existing queue_fix_pr work candidate.impact:message-lossThis issue is about lost, duplicated, misrouted, or suppressed channel messages.issue-rating: 🐚 platinum hermitGood issue quality with a plausible reproduction path needing some confirmation.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions