Skip to content

perf(serverless): dispatch queued jobs without polling - #630

Open
deanq wants to merge 1 commit into
mainfrom
deanq/sls-810-event-driven-dispatch
Open

deanq wants to merge 1 commit into
mainfrom
deanq/sls-810-event-driven-dispatch

Conversation

@deanq

@deanq deanq commented Oct 19, 2026

Copy link
Copy Markdown
Member

Summary

JobScaler.run_jobs checked the job queue on a 100ms poll (asyncio.sleep(0.1) / asyncio.wait(timeout=0.1)). A job that get_jobs had already fetched could wait up to 100ms before its handler started. On cold start, every worker's first job hit this delay.

  • get_jobs sets an asyncio.Event after putting jobs on the queue
  • run_jobs blocks on whichever comes first: a running job finishing, that event, or shutdown
  • The event is cleared before each drain, so a job queued during the drain re-arms it and is not missed

Why an event rather than await jobs_queue.get(): set_scale() replaces self.jobs_queue, so a getter waiting on the old queue would never wake.

Impact

Local deployed-worker simulation (fake job API, fresh container): time from job fetch to handler call went from ~100ms to ~1ms.

Test plan

  • New: idle dispatcher starts a fetched job within 50ms (fails on main)
  • New: busy dispatcher starts a second job within 50ms while the first is still running (fails on main)
  • New: idle dispatcher exits promptly on shutdown (fails on main)
  • test_rp_scale.py repeated 5x, no flakes
  • make quality-check: 1482 passed, 91.65% coverage

Linear: SLS-810

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.

馃煛 Changes recommended

Verified shutdown timing and signal-wakeup issues can leave the dispatcher blocked or delay its exit.

2 open issues
What changed in this PR

Replaces job-dispatch polling with event-driven wakeups to reduce fetched-job latency.

Changes:

  • Signals the dispatcher when jobs enter the queue.
  • Waits for queued jobs, task completion, or shutdown.
  • Adds latency tests for idle dispatch, busy dispatch, and shutdown.
File Description
tests/鈥媡est_serverless/鈥媡est_rp_scale.py Adds dispatch-latency and prompt-shutdown tests.
runpod/鈥媠erverless/鈥媘odules/鈥媟p_scale.py Replaces polling with event-based dispatch waits.

Review effort: Balanced

Comment on lines +419 to +422
waiters = {asyncio.create_task(self._jobs_available.wait())}
if self.is_alive():
# Once shutting down, the set event would wake this loop instantly.
waiters.add(asyncio.create_task(self._shutdown_event.wait()))
Comment on lines +424 to +425
done, _ = await asyncio.wait(
tasks | waiters, return_when=asyncio.FIRST_COMPLETED
@deanq
deanq force-pushed the deanq/sls-810-event-driven-dispatch branch from dcff6bc to cc57fc5 Compare October 19, 2026 17:21
run_jobs slept on a 100ms poll between queue checks, so a fetched job
waited up to 100ms before its handler started. On cold start this
delay landed on every worker's first job.

- get_jobs sets an asyncio.Event after queuing jobs
- run_jobs waits on job completion, that event, or shutdown
- Event instead of queue.get(): set_scale() replaces jobs_queue, which
  would strand a pending getter on the old queue

Linear: SLS-810
@deanq
deanq force-pushed the deanq/sls-810-event-driven-dispatch branch from cc57fc5 to 1c53709 Compare October 19, 2026 17:47
@jasonwang-runpod

Copy link
Copy Markdown
Collaborator

Didn't find any new issues beyond Copilot's 2 comments.

This branch has not been deployed

No deployments
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