-
Notifications
You must be signed in to change notification settings - Fork 289
feat: port dynamic load-based idle process scaling from Python SDK #1512
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@livekit/agents': patch | ||
| --- | ||
|
|
||
| SDK to support dynamic, load-based idle process scaling |
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -683,6 +683,25 @@ export class AgentServer { | |||||||||
| const currentlyAvailable = !isFull; | ||||||||||
| currentStatus = currentlyAvailable ? WorkerStatus.WS_AVAILABLE : WorkerStatus.WS_FULL; | ||||||||||
|
|
||||||||||
| if (isFull) { | ||||||||||
| this.#procPool.setTargetIdleProcesses(this.#opts.numIdleProcesses); | ||||||||||
|
Comment on lines
+686
to
+687
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 When worker is at full load, target idle processes is set to maximum instead of zero In
Suggested change
Was this helpful? React with 👍 or 👎 to provide feedback. |
||||||||||
| } else { | ||||||||||
| const activeJobs = this.activeJobs.length; | ||||||||||
| if (activeJobs > 0) { | ||||||||||
| const jobLoad = currentLoad / activeJobs; | ||||||||||
| if (jobLoad > 0) { | ||||||||||
| const availableLoad = Math.max(this.#opts.loadThreshold - currentLoad, 0.0); | ||||||||||
| const availableJob = Math.min( | ||||||||||
| Math.ceil(availableLoad / jobLoad), | ||||||||||
| this.#opts.numIdleProcesses, | ||||||||||
| ); | ||||||||||
| this.#procPool.setTargetIdleProcesses(availableJob); | ||||||||||
| } | ||||||||||
| } else { | ||||||||||
| this.#procPool.setTargetIdleProcesses(this.#opts.numIdleProcesses); | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| if (oldStatus != currentStatus) { | ||||||||||
| const extra = { load: currentLoad, loadThreshold: this.#opts.loadThreshold }; | ||||||||||
| if (isFull) { | ||||||||||
|
|
||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔴 spawnTasks overcounts by including tasks for processes already running jobs, preventing idle pool replenishment
In
proc_pool.ts:142,currentPendingis computed aswarmedProcQueue.items.length + spawnTasks.size. However,spawnTasksincludes tasks for processes that have already been consumed from the queue bylaunchJob()and are currently running jobs (still awaitingproc.join()atproc_pool.ts:115). This causes double-counting: idle processes appear both initems.lengthandspawnTasks, and running processes appear inspawnTasksdespite no longer being idle. As a result,toSpawn = target - currentPendingis systematically too low, and the pool never spawns replacement idle processes after jobs consume them.Concrete scenario showing the bug
With
numIdleProcesses=4, after 4 processes are warmed: queue=4, spawnTasks=4 (waiting on join). After 4 jobs consume all processes: queue=0, spawnTasks=4. A 5th job callslaunchJob()wherespawnTasks.size (4) < jobsWaitingForProcess (1)isfalse, so no demand spawn occurs. Therun()loop computescurrentPending=4, target=4, toSpawn=0. The 5th job blocks onwarmedProcQueue.get()indefinitely until a prior job finishes — a regression from the old MultiMutex approach whereentry.unlock()immediately freed a slot.Prompt for agents
Was this helpful? React with 👍 or 👎 to provide feedback.