Bug
In agents/src/worker.ts (around lines 853–862), the ASSIGNMENT_TIMEOUT message handler logs a warning and returns, but never resolves or rejects the PendingAssignment promise that is being awaited on line 859:
```ts
// ASSIGNMENT_TIMEOUT handler (simplified):
case AgentServerMessage_Message.Case.AssignmentTimeout:
logger.warn('assignment timeout');
return; // ← promise never settled
// ...
await this.#pending[req.id]?.promise; // ← hangs forever
```
Two problems result:
-
Permanent hang: await this.#pending[req.id]?.promise never resolves or rejects after a timeout fires. The worker goroutine for that job is permanently blocked.
-
Memory leak: The #pending[req.id] entry is only deleted on successful assignment (around line 698). On timeout, it is never cleaned up — each timed-out job leaks one entry from the #pending map for the lifetime of the worker.
Fix
Add a reject (or resolve) slot to the PendingAssignment type and call it in the timeout handler, then delete the entry:
```ts
case AgentServerMessage_Message.Case.AssignmentTimeout: {
const pending = this.#pending[req.id];
if (pending) {
delete this.#pending[req.id];
pending.reject(new Error(assignment timeout for job ${req.id}));
}
return;
}
```
Alternatively, use Promise.race with a timeout-rejection at the await site.
Impact
- Any job that times out during assignment permanently blocks a worker slot
#pending map grows unbounded under sustained timeout conditions
- Worker process may eventually exhaust memory or become unresponsive
Bug
In
agents/src/worker.ts(around lines 853–862), theASSIGNMENT_TIMEOUTmessage handler logs a warning and returns, but never resolves or rejects thePendingAssignmentpromise that is being awaited on line 859:```ts
// ASSIGNMENT_TIMEOUT handler (simplified):
case AgentServerMessage_Message.Case.AssignmentTimeout:
logger.warn('assignment timeout');
return; // ← promise never settled
// ...
await this.#pending[req.id]?.promise; // ← hangs forever
```
Two problems result:
Permanent hang:
await this.#pending[req.id]?.promisenever resolves or rejects after a timeout fires. The worker goroutine for that job is permanently blocked.Memory leak: The
#pending[req.id]entry is only deleted on successful assignment (around line 698). On timeout, it is never cleaned up — each timed-out job leaks one entry from the#pendingmap for the lifetime of the worker.Fix
Add a
reject(orresolve) slot to thePendingAssignmenttype and call it in the timeout handler, then delete the entry:```ts
case AgentServerMessage_Message.Case.AssignmentTimeout: {
const pending = this.#pending[req.id];
if (pending) {
delete this.#pending[req.id];
pending.reject(new Error(
assignment timeout for job ${req.id}));}
return;
}
```
Alternatively, use
Promise.racewith a timeout-rejection at the await site.Impact
#pendingmap grows unbounded under sustained timeout conditions