Skip to content

feat(relay): alert on relay cell table lock convoys - #22446

Merged
Jinwoo-H merged 2 commits into
mainfrom
relay-lock-alert
Sep 23, 2026
Merged

Jinwoo-H merged 2 commits into
mainfrom
relay-lock-alert

Conversation

@Jinwoo-H

@Jinwoo-H Jinwoo-H commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

ELI5

Sometimes one relay process locks the table of relay cells for several seconds. While it holds that lock, every host connect and reservation change in the whole fleet waits and then fails. Nothing paged on this. This PR adds two paging alerts: one fires when a cell holds that lock for a second or longer, and one fires when those failures pile up to 20 or more in a minute. Holds by the director are shown on a third policy that does not page.

What Changed

Before: the stalls only showed up when someone went digging in logs. On-call had no signal and no first step.

After: two new Cloud Monitoring alert policies page the existing relay channel, and a third one records director holds without paging.

  • Cell table lock held over 1 second. This is a new log-based metric on the relay's 30-second runtime sample. The filter keeps only samples of 1,000 ms or more. The value is kept as a distribution labelled with the process role and the cell. The bar lives in the filter, so the alert is on the sampled milliseconds, not on a count of lines. The paging policy selects samples whose role is cell only.
  • Director cell table lock held over 1 second. This policy reads the same metric for the role director and has no notification channel. Director holds of 1 to 2.5 seconds happen a few times a day even with rehoming paused, and pausing rehome does not stop them. Paging on them would send on-call a runbook that says do nothing.
  • Lock timeout burst. This is a new counter on the shared Cloud SQL instance's Postgres log. It counts relay statements that Postgres cancelled after they waited out their lock timeout. The alert fires at 20 or more in a minute.

Both paging policies tell the reader what to do. If an asia-east2 cell held the lock, pause regional rehoming with the Operate Relay Production Rehome workflow, action pause. If the burst alert fires with no cell hold in the same minute, look at the director policy instead of pausing rehome, and do not drain or restart cells. The runbook section is in cloud/docs/relay-incident-monitor.md.

The two metric filters, as rendered by the plan. The paging hold policy adds metric.label."role"="cell" on top of the first.

((resource.type="cloud_run_revision" AND (resource.labels.service_name="orca-cloud-relay")) OR (resource.type="gce_instance" AND jsonPayload.role="cell")) AND jsonPayload.event="orca_relay_runtime_metrics" AND jsonPayload.cellInventoryHoldMsMax>=1000
resource.type="cloudsql_database" AND resource.labels.database_id="onorca-cloud:orca-cloud-auth-db" AND textPayload:"db=orca_relay," AND textPayload:"canceling statement due to lock timeout"

Why

The lock hold is the cause, and the cancels are the damage. An alert on each lets on-call see both the holder and the blast radius.

The cancel counter reads the Postgres log, not the relay's own lock-timeout counter. The relay counter misses most of the waiters: row-level waits and the reservation updates were 122 of 134 cancels in one recorded episode.

Fail-fast lock refusals are left out of the cancel count on purpose. The brief asked to consider them, but background sweeps produce them by design. They ran at 9,690 in one hour with rehoming paused, about 160 per minute. Counting them would keep a 20-per-minute alert permanently firing.

db=orca_relay, keeps the auth database on the same instance out. The push database is on a different instance and never matches.

Linked Issue

No issue. This is step 0 of the relay lock convoy fix plan.

Visual Proof

N/A. This change adds monitoring configuration and no UI.

Testing

Replay, not waiting. Log-based metrics count only entries written after they exist. So both exact filter strings were replayed with read-only gcloud logging read over the root-cause window, 2026-09-20 14:00 to 2026-09-22 15:00 UTC, and over the paused period since then.

Paging lock hold filter, cell samples only, 49 h window:

Holder Samples at or above 1,000 ms Range
c27 28 3,531-3,622 ms
c28 32 3,527-3,915 ms
c29 33 3,527-3,624 ms
director 0 not paged; 9 samples of 1,007-1,801 ms go to the non-paging policy
US cells 0 highest US cell hold was 227 ms
  • That is all 93 recorded asia-east2 holds and no director holds.
  • The investigation reported the Asia holds as 3,601-3,609 ms. The raw samples actually span 3,527-3,915 ms, which does not change the match.
  • From 2026-09-22 15:00 to 2026-09-23 07:30, with rehoming paused, the paging filter matched 0 samples. The four director holds in that period went to the non-paging policy.

Cancel filter, 49 h window: 6,104 cancels, which matches the investigation exactly. "Peak" below is the highest count in any rolling 60-second window.

Period Cancels Peak Firing episodes
09-20 14:00-20:00, before rehome commits 260 58 1
09-20 20:00 to 09-22 03:30, rehome on 5,013 134 71
09-22 03:30-09:00, paused 109 14 0
09-22 09:00-11:25, re-enabled at generation 31 685 130 7
09-22 11:25-15:00, paused at generation 32 37 3 0
09-22 15:00 to 09-23 07:00, still paused 326 25 1
  • 88 calendar minutes reached 20 or more cancels in the 49 h window. Every one of them overlaps an asia-east2 hold.
  • Every one of the 93 asia-east2 holds has a minute of at least 32 cancels in its window. The median is 53.
  • The one episode before rehome commits began lines up with an asia-east2 hold at 09-20 14:19.

The one burst while paused is at 2026-09-23 04:23 UTC. It had 25 cancels behind a 2,457 ms director hold. Rehoming was paused, and no rehome commits were logged in that period. The filter was not tuned to hide it. It is a real director-held stall, the residual the investigation left open. The burst documentation and the runbook now say to check the director policy when no cell hold appears in the same minute.

Plan census. The Terraform root that owns these resources also owns the 29 cell templates. All plans ran with -refresh=false -lock=false against production state; no apply was run.

  • The targeted plan, -target on the five new addresses, shows Plan: 5 to add, 0 to change, 0 to destroy:
    • google_logging_metric.relay_incident["cloud_sql_lock_timeouts"]
    • google_logging_metric.relay_long_cell_inventory_hold
    • google_monitoring_alert_policy.relay_lock_timeout_burst
    • google_monitoring_alert_policy.relay_long_cell_inventory_hold
    • google_monitoring_alert_policy.relay_director_cell_inventory_hold
  • The full untargeted plan is 52 to add, 66 to change, 35 to destroy. The same plan at base 51c3434851 is 47 to add, 66 to change, 35 to destroy.
  • The planned address lists differ by exactly the five creates above.
  • On the first revision, the other 120 planned changes had byte-identical before and after values in both plans. The second revision edits only the new resources.
  • Both plans carry pre-existing drift: 29 template replacements, 29 group-manager updates and 28 backend updates. They also delete the old push database, its user and its secret on the shared auth instance. Those resources left the code in revert: hold mobile push feature for user testing #19203 but are still in state. The live push gateway uses its own dedicated instance, which the plan does not touch.

Do not apply this root untargeted. Applying is a separate operator step. Use the five -target flags above and confirm the plan shows 5 to add and nothing else.

Checks run:

  • terraform fmt -check -recursive and terraform validate pass.

  • A new test, cloud/dev/scripts/relay-lock-contention-alerts.test.mjs, pins the pieces a rename on either side would silently break. It checks that the hold field exists in the relay emitter and that the cancel filter matches the relay database only. It checks that the cancel filter excludes fail-fast refusals and the lock_timeout statement echo. It also checks the thresholds, the bucket floor and the notification channel. It checks that the paging hold policy selects only the cell role and that the director policy has no notification channel. Changing a paging condition to the director role makes the test fail. The test is added to pretest.

  • The existing terraform-root-partition fixture now includes the four new resource families. That test, the region-hint test and the connection-budget test all pass.

  • I manually tested these changes locally

  • Automated tests added/updated, or explained why not below

AI Disclosure

Review

Agent skill upstream boundary

  • Not applicable, or this change follows docs/reference/agent-skill-sharing-upstream-boundary.md and copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

The two paging policies are expected to be noisy while regional rehoming runs with asia-east2 sources. That is intended, because each firing is a fleet-wide stall of several seconds. A cell that has stopped reporting emits no hold sample, so these alerts catch lock convoys, not outages. The existing liveness checks stay in place.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

Adds a log-based metric and alert for cell-inventory lock holds of at
least 1,000 ms, and a Cloud SQL log metric and alert for relay-only lock
timeout cancels at 20 or more per minute. NOWAIT refusals are excluded:
background sweeps produce about 160 per minute even with rehome paused.

Replayed over 2026-09-20 14:00 to 2026-09-22 15:00 UTC: the hold filter
matches all 93 asia-east2 rehome holds plus 9 director holds, and every
one of the 88 cancel burst minutes overlaps an asia-east2 hold.

Claude-Session: ced32ebb-7155-4413-adad-1eccd14c2010

@pullfrog pullfrog 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.

ℹ️ No critical issues. One doc-accuracy nit inline.

Reviewed changes

  • Long-hold log metric + alert — new google_logging_metric.relay_long_cell_inventory_hold thresholds the existing cellInventoryHoldMsMax runtime field at >=1000 in the log filter, with a new google_monitoring_alert_policy.relay_long_cell_inventory_hold splitting cloud_run_revision/gce_instance conditions and grouping by cell_id.
  • Lock-timeout counter + burst alert — local.relay_incident_metrics.cloud_sql_lock_timeouts reads Postgres cancels for db=orca_relay, only, and google_monitoring_alert_policy.relay_lock_timeout_burst fires at ≥20/min via ALIGN_SUM/REDUCE_SUM.
  • Tests, fixture, docs — new relay-lock-contention-alerts.test.mjs pins the wiring, families.json gains the three new families, and relay-incident-monitor.md documents the response.

Verified the emitted metric type resolves to the same name the burst policy hardcodes (orca_relay_${each.key} → orca_relay_cloud_sql_lock_timeouts), that RelayProcessCounts spreads CellInventoryHoldCounts into the orca_relay_runtime_metrics payload, and that the new test plus terraform-root-partition.test.mjs both pass locally. The percentile + REDUCE_MAX + threshold-0 hold condition matches the existing relay_gce_connection_headroom pattern, which is the only valid scalar aligner for a DELTA DISTRIBUTION in condition_threshold.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

Comment thread cloud/docs/relay-incident-monitor.md Outdated
rehome commits (about 3.6 s each) and 9 director holds of 1.0-1.8 s, and every
one of the 88 burst minutes overlapped an asia-east2 hold. First response: if
the hold names an asia-east2 cell, pause regional rehoming through
`Operate Relay Production Rehome` with action `pause`. If rehoming is already

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.

The Operate Relay Production Rehome dispatch input is named mode, not an action, so "action pause" sends on-call looking for a field that doesn't exist. The same phrasing is repeated in both new alert documentation.content strings.

Technical details
# Workflow input name mismatch

## Affected sites
- `cloud/docs/relay-incident-monitor.md:286` — "`Operate Relay Production Rehome` with action `pause`"
- `cloud/infra/terraform/relay-observability.tf:872` — hold-policy documentation: "workflow, action `pause`"
- `cloud/infra/terraform/relay-observability.tf:906` — burst-policy documentation: "workflow, action `pause`"

## Required outcome
- The three strings name the actual workflow input (`mode: pause`) so the first-response instruction is directly actionable.

## Suggested approach (optional)
- Replace "action `pause`" with "mode `pause`". Optionally add the required typed `confirmation: PAUSE_REGIONAL_REHOMING` that `cloud/docs/relay-workflows.md:508` documents, since the alert text is what on-call reads first.

@coderabbitai

coderabbitai Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Advanced

Run ID: a59900df-f41b-4898-a9b6-0e54c940ffc6

📥 Commits

Reviewing files that changed from the base of the PR and between 51c3434 and e775956.

📒 Files selected for processing (5)
  • cloud/dev/fixtures/terraform-root-partition/families.json
  • cloud/dev/scripts/relay-lock-contention-alerts.test.mjs
  • cloud/docs/relay-incident-monitor.md
  • cloud/infra/terraform/relay-observability.tf
  • cloud/package.json

Included review availability: Your plan provides up to 10 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The change adds Cloud SQL and runtime metrics for relay lock-timeout cancellations and long cell-inventory holds. It adds alert policies for lock-timeout bursts and long holds, registers the Terraform resources in the fixture family list, and adds tests to the pretest script. The incident monitor documentation describes policy thresholds, replay results, and response procedures.

Priority: ⬆️ High

Merge Risk: ⚪ Minimal · up to e7759

This change adds alerts for relay lock convoys and long cell-inventory table holds. It does not change runtime relay behavior, so a mistake would at most cause missed or noisy alerts, not user-facing failures. It is ready to merge. Before on-call relies on the new pause guidance, update it to name the rehome workflow's mode input rather than action.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the change, rationale, testing, visual-proof status, and operational impact. However, it explicitly states that there is no linked issue, while the template requires one. Add a link to the issue this PR addresses. If no issue exists, create one and link it in this section; the template says an issue must always be linked.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 1…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes the main change: adding alerts for relay cell table lock convoys.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Commit to this branch
  • Create a new PR
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Director holds of 1-2.5 s recur several times a day with rehoming paused,
and pausing rehome does not stop them. The paging hold policy now selects
role=cell samples only; a separate policy with no notification channel
keeps director holds visible. The burst documentation no longer claims no
burst happens while paused, and the runbook points a burst with no cell
hold at the director policy.

Replayed cell-only: 93 of 93 asia-east2 holds, 0 director holds over
2026-09-20 14:00 to 2026-09-22 15:00 UTC; 0 from then to 2026-09-23 07:30.

Claude-Session: ced32ebb-7155-4413-adad-1eccd14c2010
@Jinwoo-H
Jinwoo-H merged commit a2a78ab into main Sep 23, 2026
24 of 26 checks passed
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