Skip to content

feat: SLS-497 Add explicit prestart hooks to the runpod-python SDK - #570

Open
jasonwang-runpod wants to merge 4 commits into
mainfrom
jasonwang/sls-497-explicit-prestart-hooks
Open

feat: SLS-497 Add explicit prestart hooks to the runpod-python SDK#570
jasonwang-runpod wants to merge 4 commits into
mainfrom
jasonwang/sls-497-explicit-prestart-hooks

Conversation

@jasonwang-runpod

@jasonwang-runpod jasonwang-runpod commented Aug 19, 2026

Copy link
Copy Markdown

Problem

Workers often load models or start inference engines before calling runpod.serverless.start(). The SDK cannot observe that work, so prestart failures leave requests in IN_QUEUE while the useful error remains only in worker logs.

Solution

Add explicit prestart hooks that the SDK supervises before handler execution.

  • Workers register ordered sync or async hooks with @runpod.serverless.register_prestart_hook. One optional timeout covers the complete prestart phase.
  • Queue workers continue job intake during prestart but hold handler execution until every hook succeeds.
  • A failure or timeout is attached to a request as prestart_failed, then the worker drains and exits.
  • Local input and single-worker hosted API mode finish prestart before invoking or serving the handler. Realtime and multi-process hosted API modes remain unsupported.
  • Prestart and handler failures include bounded stdout and stderr logs.

Depends on: https://github.com/runpod/ai-api/pull/1023. AI API should deploy first so it classifies prestart_failed before this SDK emits it.

Testing

  • uv run pytest --no-cov -q: 700 passed.
  • Focused Ruff checks and formatting checks passed.
  • A real A40 vLLM endpoint completed after successful prestart, failed with the full payload after an engine startup exception, and failed with PrestartTimeout under a five-second bound.

Supersedes #567.

A handler that dies during a model load or a CUDA fault usually explains itself on
stdout/stderr, but only the exception reached the platform, so the useful part was
lost. Tee both streams into a per-context ring buffer and attach the tail to the
error the worker reports. Every reported field is clipped so a huge message or log
cannot push the job-done body past its limit.
Startup work placed before runpod.serverless.start() ran outside the SDK's view: a
model load that hung or crashed left requests sitting in IN_QUEUE until the TTL
expired, with the reason buried in worker logs.

Accept an optional initializer and init_timeout. The worker now runs the
initializer as a fourth concurrent task, keeps taking requests, and holds handler
execution until initialization finishes. If initialization fails, the worker
reports the reason and its captured logs against the request it is holding through
the existing job-done route, fails any request a long-poll returns afterwards, and
exits so the platform respawns it under existing backoff.
Comment thread runpod/serverless/modules/rp_prestart.py
Comment thread runpod/serverless/modules/rp_prestart.py
Comment thread runpod/serverless/modules/rp_prestart.py
Comment thread runpod/serverless/modules/rp_scale.py
Comment thread tests/test_serverless/test_prestart.py
Comment thread runpod/serverless/modules/rp_prestart.py
Comment thread runpod/serverless/modules/rp_prestart.py
Comment thread runpod/serverless/modules/rp_scale.py
Comment thread tests/test_serverless/test_prestart.py
Comment thread runpod/serverless/modules/rp_prestart.py

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 supervised prestart hooks across supported Serverless worker modes, including startup-failure reporting and bounded stdout/stderr capture.

Changes:

  • Adds ordered sync/async prestart hooks with optional phase timeout.
  • Gates handlers during initialization and drains failed queue workers.
  • Captures bounded logs for startup and handler failures.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated no comments.

Show a summary per file
File Description
runpod/serverless/__init__.py Exposes hooks and validates runtime modes.
runpod/serverless/worker.py Installs output capture for workers.
runpod/serverless/modules/rp_prestart.py Implements hook registration and execution.
runpod/serverless/modules/rp_capture.py Implements bounded contextual output capture.
runpod/serverless/modules/rp_scale.py Integrates queue gating, failure delivery, and shutdown.
runpod/serverless/modules/rp_local.py Runs hooks before local handlers.
runpod/serverless/modules/rp_fastapi.py Runs hooks through FastAPI lifespan.
runpod/serverless/modules/rp_job.py Attaches captured logs to handler failures.
docs/serverless/worker.md Documents prestart configuration and modes.
tests/test_serverless/test_prestart.py Tests the public hook contract and mode guards.
tests/test_serverless/test_prestart_lifecycle.py Tests queue lifecycle and process termination.
tests/test_serverless/test_capture.py Tests capture and output bounds.
tests/test_serverless/test_modules/test_local.py Tests local prestart behavior.
tests/test_serverless/test_init.py Verifies the new public export.

馃挕 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@jasonwang-runpod
jasonwang-runpod marked this pull request as ready for review August 19, 2026 22:16
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.

3 participants