fix: only preempt idle containers when scheduled tasks enqueue

Containers that finish work but stay alive in waitForIpcMessage() block
queued scheduled tasks. Previous approaches killed active containers
mid-work. This fix tracks idle state via the session-update marker
(status: success, result: null) and only preempts when the container
is idle-waiting, not actively working.

Closes #293

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
gavrielc
2026-02-21 21:16:13 +02:00
parent 6f177adafe
commit 93bb94ff55
4 changed files with 145 additions and 0 deletions

View File

@@ -16,6 +16,7 @@ const BASE_RETRY_MS = 5000;
interface GroupState {
active: boolean;
idleWaiting: boolean;
pendingMessages: boolean;
pendingTasks: QueuedTask[];
process: ChildProcess | null;
@@ -37,6 +38,7 @@ export class GroupQueue {
if (!state) {
state = {
active: false,
idleWaiting: false,
pendingMessages: false,
pendingTasks: [],
process: null,
@@ -92,6 +94,9 @@ export class GroupQueue {
if (state.active) {
state.pendingTasks.push({ id: taskId, groupJid, fn });
if (state.idleWaiting) {
this.closeStdin(groupJid);
}
logger.debug({ groupJid, taskId }, 'Container active, task queued');
return;
}
@@ -119,6 +124,18 @@ export class GroupQueue {
if (groupFolder) state.groupFolder = groupFolder;
}
/**
* Mark the container as idle-waiting (finished work, waiting for IPC input).
* If tasks are pending, preempt the idle container immediately.
*/
notifyIdle(groupJid: string): void {
const state = this.getGroup(groupJid);
state.idleWaiting = true;
if (state.pendingTasks.length > 0) {
this.closeStdin(groupJid);
}
}
/**
* Send a follow-up message to the active container via IPC file.
* Returns true if the message was written, false if no active container.
@@ -163,6 +180,7 @@ export class GroupQueue {
): Promise<void> {
const state = this.getGroup(groupJid);
state.active = true;
state.idleWaiting = false;
state.pendingMessages = false;
this.activeCount++;
@@ -196,6 +214,7 @@ export class GroupQueue {
private async runTask(groupJid: string, task: QueuedTask): Promise<void> {
const state = this.getGroup(groupJid);
state.active = true;
state.idleWaiting = false;
this.activeCount++;
logger.debug(