Skip to content

fix(decdn_node): make the /metrics readiness gate advisory (no false-fail) - #26

Merged
thiras merged 2 commits into
mainfrom
fix/decdn-node-advisory-readiness-probe
Jul 12, 2026
Merged

thiras merged 2 commits into
mainfrom
fix/decdn-node-advisory-readiness-probe

Conversation

@thiras

@thiras thiras commented Jul 12, 2026 •

Copy link
Copy Markdown
Contributor

Problem

make deploy (ansible-playbook playbooks/site.yml) hard-failed on the Wait for the node metrics endpoint task in roles/decdn_node/tasks/main.yml. The task waited ~60s (30×2s) for http://127.0.0.1:9090/metrics to return 200, then failed the play on timeout.

But decdn-node binds its loopback metrics/admin listeners only after its startup bootstrap completes — behind a retrying PaymentChannel buyer-side approve (an upstream startup-ordering issue in decdn/decdn, tracked there, not here). On a completely healthy node this can lag process start by many minutes. Observed live: service active (running), NRestarts=0, QUIC udp/4433 listening, on-chain isActiveNode=true — yet tcp 9090/9191 not yet bound, so the 60s probe timed out with "Connection refused" and the deploy failed every time.

Bumping retries to cover the worst case would hang every deploy for that whole window — unacceptable. So the probe becomes advisory instead.

What changed (Ansible role only)

  • Advisory on timeout. A connection-refused/timeout (uri status -1) now warns via a conditional debug rather than failing the play (failed_when is scoped, not blanket).
  • Still fails loud on a real fault. A metrics endpoint that answers with a non-200 status (e.g. 500 from a broken handler) fails the deploy — failed_when: status not in [-1, 200], keeping AGENTS.md hard-rule 4 (fail loud).
  • Liveness gate preserved and described honestly. The service_facts + state == 'running' assert stays as the backstop, but comments/README/warning now state plainly it is not a full health check (a Type=simple unit reports running even when wedged), so a persistent timeout warrants out-of-band verification (curl, journalctl for "node runtime ready").
  • Configurable window. New role vars decdn_readiness_retries (30) / decdn_readiness_delay (2), documented in defaults/main.yml and the role README's new Readiness section.
  • Molecule coverage. New slow-readiness scenario: a marker-gated "late-bind" stub mode (never binds /metrics, stays alive) drives the timeout path and verifies the deploy succeeds with the unit running but 9090 unbound. Would catch a straight revert of the advisory behavior. CI comment updated for the third scenario.

Scope note: the ~27-min late bind is a decdn core binary matter tracked separately in decdn/decdn (metrics/admin should bind early, independent of the buyer bootstrap). This PR only makes the Ansible deploy robust against a slow-but-healthy startup.

Testing

  • make lint-ansible — ansible-lint production profile, 0 failures
  • make lint — all pre-commit hooks pass
  • molecule test -s slow-readiness — converge survives the timeout, verify asserts running-but-no-metrics ✅
  • molecule test -s default — ready/200 path unchanged ✅
  • Local check of the scoped failed_when: -1=advisory, 200=ready, 500/404=fail-loud

Review

Reviewed via /pr-review-toolkit:review-pr (code, tests, comments, silent-failure). Applied the resulting fixes: scoped failed_when, honest liveness-gate prose, CI-comment + prose-rot cleanup. Deferred the crash-loop negative-test scenario as a follow-up.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added configurable, best-effort readiness checks for the node’s /metrics endpoint.
    • Readiness timeouts now issue warnings without blocking deployment, while unexpected HTTP responses still fail validation.
    • Added a dedicated regression scenario for services that start slowly or do not expose metrics immediately.
  • Documentation

    • Updated readiness guidance to clarify probe behavior and service-state limitations.

…fail)

The decdn_node role hard-failed `make deploy` on the "Wait for the node
metrics endpoint" task after ~60s, but a healthy decdn-node binds its
loopback metrics/admin listeners only after its startup bootstrap
completes (behind the PaymentChannel buyer bootstrap — an upstream
startup-ordering issue in decdn/decdn), which can lag process start by
many minutes. Result: healthy nodes failed the deploy every time, while
the systemd unit was active and QUIC was serving.

Make the probe advisory without hanging the deploy:

- On TIMEOUT (connection-refused, status -1) the probe now WARNS via a
  conditional debug instead of failing the play. A non-200 *answer*
  (e.g. 500 from a broken /metrics handler) still fails loud — scoped
  failed_when keeps AGENTS.md's fail-loud posture for genuine faults.
- The systemd service-state assert remains the liveness gate; comments,
  README, and the operator-facing warning are explicit that it is a
  backstop (a Type=simple unit reports `running` even when wedged), so a
  persistent timeout is not provably benign — verify out-of-band.
- Bound the probe window via new role vars decdn_readiness_retries /
  decdn_readiness_delay (default ~60s), documented in defaults + README.
- Add a `slow-readiness` molecule scenario: a marker-gated "late-bind"
  stub mode drives the timeout path and verifies the deploy succeeds with
  the unit running but /metrics unbound. Update the CI comment for the
  new scenario.

Verified: ansible-lint (production) + pre-commit clean; molecule default
and slow-readiness scenarios pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 12, 2026 00:44
@coderabbitai

coderabbitai Bot commented Jul 12, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@thiras, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 48 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 79ea03ac-6ee6-4927-8077-c5a9397e0249

📥 Commits

Reviewing files that changed from the base of the PR and between 90c9468 and eba81a9.

📒 Files selected for processing (1)
  • ansible/roles/decdn_node/tasks/main.yml
📝 Walkthrough

Walkthrough

The node role now performs an advisory /metrics readiness probe with configurable retries and delay. A new Molecule scenario simulates an unbound endpoint, verifies deployment continues with the service running, and documents the scenario in the workflow.

Changes

Advisory readiness probe

Layer / File(s) Summary
Configurable probe behavior
ansible/roles/decdn_node/defaults/main.yml, ansible/roles/decdn_node/tasks/main.yml, ansible/roles/decdn_node/README.md
Adds retry and delay settings, makes metrics timeouts non-fatal with warnings, fails on unexpected responses, and documents the resulting readiness semantics.

Slow-readiness scenario

Layer / File(s) Summary
Stub and scenario setup
ansible/molecule/default/files/decdn-node-stub, ansible/molecule/slow-readiness/*
Adds marker-controlled no-metrics behavior and configures a Molecule scenario with placeholder secrets, a short probe window, and the node role.
Scenario verification and workflow coverage
ansible/molecule/slow-readiness/verify.yml, .github/workflows/molecule.yml
Checks that port 9090 is unbound while decdn-node.service remains running and documents the scenario in the full Molecule test list.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Molecule
  participant decdn_node
  participant decdn-node-stub
  participant systemd
  Molecule->>decdn_node: Run converge with short readiness window
  decdn_node->>systemd: Start decdn-node.service
  systemd->>decdn-node-stub: Start stub with no-metrics marker
  decdn_node->>decdn-node-stub: Probe /metrics
  decdn-node-stub-->>decdn_node: Endpoint remains unbound
  decdn_node->>systemd: Check service state
  systemd-->>decdn_node: Service is running
  Molecule->>decdn_node: Verify timeout path and listener state
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: making the /metrics readiness gate advisory to avoid false deployment failures.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/decdn-node-advisory-readiness-probe

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.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new Molecule test scenario (slow-readiness) and updates the decdn_node Ansible role to make the /metrics readiness probe advisory on timeout. This prevents slow-starting nodes from failing the deployment while still ensuring that non-200 responses trigger a failure. The stub daemon was also updated to simulate late-binding behavior. The review feedback suggests skipping the readiness probe and its warning task during Ansible check mode to avoid unnecessary delays and false warnings. Additionally, it is recommended to gather service facts conditionally to make the role more robust and self-contained.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread ansible/roles/decdn_node/tasks/main.yml
Comment thread ansible/roles/decdn_node/tasks/main.yml Outdated
Comment thread ansible/roles/decdn_node/tasks/main.yml

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the decdn_node Ansible role to avoid false deployment failures when /metrics is slow to come up on otherwise-healthy nodes by making the /metrics readiness probe advisory on timeout while still failing loudly on real non-200 responses. It also documents the behavior and adds a Molecule regression scenario to ensure the advisory-timeout path stays covered.

Changes:

  • Make the /metrics readiness probe bounded + advisory on timeout, while failing on non-200 responses that indicate a real endpoint fault.
  • Add configurable probe window knobs (decdn_readiness_retries, decdn_readiness_delay) and document readiness semantics in the role README.
  • Add a new Molecule slow-readiness scenario plus stub support to validate the timeout-with-running-service behavior.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
ansible/roles/decdn_node/tasks/main.yml Adjusts readiness logic: advisory timeout warning, scoped failed_when, keeps service-state backstop.
ansible/roles/decdn_node/README.md Documents advisory readiness behavior, tuning knobs, and verification steps.
ansible/roles/decdn_node/defaults/main.yml Introduces and documents default readiness probe window variables.
ansible/molecule/slow-readiness/molecule.yml New Molecule scenario to exercise the advisory timeout path.
ansible/molecule/slow-readiness/prepare.yml Stages marker + required placeholder files to force “no metrics bind” stub behavior.
ansible/molecule/slow-readiness/converge.yml Converges role with a tiny readiness window to quickly hit timeout behavior.
ansible/molecule/slow-readiness/verify.yml Verifies “unit running but no metrics socket” end state.
ansible/molecule/default/files/decdn-node-stub Adds marker-gated “never bind metrics” mode to simulate late-bind behavior.
.github/workflows/molecule.yml Updates comment to reflect the additional Molecule scenario run by --all.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ansible/roles/decdn_node/tasks/main.yml Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ansible/roles/decdn_node/tasks/main.yml`:
- Around line 399-414: Update the readiness probe’s until condition for
decdn_metrics_probe so retries continue only while status is -1 (connection
refused or unavailable) and stop when any response status is received. Preserve
failed_when so status 200 succeeds, -1 remains advisory after exhaustion, and
other statuses fail immediately.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 666e0ece-be63-4920-a45a-c4152c97e2e4

📥 Commits

Reviewing files that changed from the base of the PR and between 22e8edd and 90c9468.

📒 Files selected for processing (9)
  • .github/workflows/molecule.yml
  • ansible/molecule/default/files/decdn-node-stub
  • ansible/molecule/slow-readiness/converge.yml
  • ansible/molecule/slow-readiness/molecule.yml
  • ansible/molecule/slow-readiness/prepare.yml
  • ansible/molecule/slow-readiness/verify.yml
  • ansible/roles/decdn_node/README.md
  • ansible/roles/decdn_node/defaults/main.yml
  • ansible/roles/decdn_node/tasks/main.yml

Comment thread ansible/roles/decdn_node/tasks/main.yml
Address PR review feedback on the advisory readiness probe:

- Fail-fast on a real fault: change the probe's `until` to stop as soon as
  the endpoint ANSWERS (status != -1) instead of only on 200. A persistent
  500 now surfaces on the first attempt via failed_when rather than after
  the whole retry window; connection-refused (-1) still retries through the
  window and stays advisory. (CodeRabbit)
- Guard the probe + warn with `not ansible_check_mode`: uri skips in check
  mode, which left the registered status unset and fired the readiness
  warning spuriously on every `make check`. (Gemini)
- Print the curl/journalctl verification hints on their own lines via a
  literal block scalar, and parenthesize the retries×delay math. (Copilot)

Kept the unconditional `service_facts` gather (a conditional
`when: ... is not defined` would risk asserting against stale, pre-start
facts — the fresh gather is required for the running-state assert).

Verified: fail-fast on 500 (attempt 1), advisory on refused, check-mode
skips both tasks; ansible-lint + yamllint clean; molecule default and
slow-readiness pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@thiras
thiras merged commit 9013a7c into main Jul 12, 2026
9 checks passed
@thiras
thiras deleted the fix/decdn-node-advisory-readiness-probe branch July 12, 2026 01:03
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.

2 participants