Skip to content

feat(serverless): report fitness failure to host before force-exit#537

Open
deanq wants to merge 3 commits into
deanq/sls-379-fitness-force-killfrom
deanq/sls-380-worker-fitness-report
Open

feat(serverless): report fitness failure to host before force-exit#537
deanq wants to merge 3 commits into
deanq/sls-379-fitness-force-killfrom
deanq/sls-380-worker-fitness-report

Conversation

@deanq

@deanq deanq commented Jul 10, 2026

Copy link
Copy Markdown
Member

What

Worker side of SLS-380. On a startup fitness-check failure, the worker sends one best-effort report to the host (over the existing ping channel) just before force-exiting, so the host can emit a queryable worker.fitness_failed event. Follow-up to SLS-379 (#536).

Details

  • _report_unhealthy(check, reason) in rp_fitness.py: single GET to RUNPOD_WEBHOOK_PING (same URL/creds as the heartbeat) with status=unhealthy, check=<check name>, reason=<ErrorType: message>[:256], runpod_version. Bounded 2s timeout, no retries.
  • Wired into the failure branch of run_fitness_checks, before the force-exit. The report is fully swallowed and the call site is wrapped, so it can never delay or block _terminate_unhealthy(1) (the SLS-379 exit guarantee).
  • Off-platform no-op: skipped when RUNPOD_WEBHOOK_PING or RUNPOD_AI_API_KEY is unset (local/test).

Stacking

Based on the SLS-379 branch (deanq/sls-379-fitness-force-kill, PR #536) because the report only makes sense with the os._exit force-kill. Retarget to main once #536 merges.

Test plan

  • make quality-check: 532 passed, coverage 94.18%.
  • New tests: report posts correct check/reason; skipped without ping URL / without API key; truncates reason to 256; swallows HTTP errors; failure path reports before exit (and the SLS-379 subprocess test proves the process still dies).

Consumed by

The ai-api host PR that reads status=unhealthy and emits @sls.event:worker.fitness_failed. This PR degrades to a no-op if the host ignores the param.

Follow-ups (from final review, non-blocking)

  • Worker report is unauthenticated at the host (inherits the ping endpoint's posture); dashboard-only scope avoids automated triggers.
  • Optional: debug-log on report skip/success/failure for diagnosability.

SLS-380

@capy-ai

capy-ai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Capy auto-review is paused for this organization because the usage-cycle auto-review limit has been reached. Increase the limit or turn it off in billing settings to resume automatic reviews.

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

Adds a best-effort “fitness failure” report from the worker to the host right before the existing force-exit path, allowing the host to emit a queryable worker.fitness_failed event without weakening the SLS-379 hard-exit semantics.

Changes:

  • Introduces _report_unhealthy(check, reason) to send a single GET over the existing ping channel with status=unhealthy, check, reason (truncated), and runpod_version.
  • Wires the report into run_fitness_checks()’s failure path immediately before _terminate_unhealthy(1), swallowing all errors.
  • Extends the existing force-kill regression test suite with new coverage for the report behavior and ordering.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
runpod/serverless/modules/rp_fitness.py Adds _report_unhealthy and calls it on fitness-check failure before force-exit.
tests/test_serverless/test_modules/test_fitness/test_force_kill.py Adds unit tests covering the unhealthy report behavior and “report before exit” ordering.

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

Comment on lines +113 to +115
# Bound the best-effort unhealthy report so it never delays the exit.
_REPORT_TIMEOUT_SECONDS = 2

Comment on lines +121 to +125
Sends a single GET to the ping URL (same URL/credentials the heartbeat
uses) with status=unhealthy plus the failing check name and reason, so the
host can emit a queryable worker.fitness_failed event. Any failure — no
ping URL, no API key, HTTP error, timeout — is swallowed: this must never
delay or block the os._exit that follows.
Comment on lines +280 to +285
# Best-effort report to the host so the failure is queryable; never
# allowed to block the force-exit below.
try:
_report_unhealthy(check_name, f"{error_type}: {error_message}")
except Exception: # never let reporting block the force-exit
pass
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