fix: cap blocked-pending counter to prevent unbounded drain loops
In busy channels, many messages arrive during a non-speaker turn, each incrementing the blocked-pending counter. Without a cap the counter grows faster than it drains, causing the speaker to spin indefinitely consuming NO_REPLY completions. Cap at MAX_BLOCKED_PENDING=3 in both incrementBlockedPending and markTurnStarted (retroactive cap to recover from accumulated debt). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -55,8 +55,22 @@ export function getInitializingChannels(): Set<string> {
|
|||||||
return _G._tmInitializingChannels as Set<string>;
|
return _G._tmInitializingChannels as Set<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum blocked-pending entries tracked per agent per channel.
|
||||||
|
* Caps the drain time: in a busy channel many messages can arrive during a non-speaker
|
||||||
|
* turn, each incrementing the counter. Without a cap the counter grows unboundedly.
|
||||||
|
* Also applied retroactively in markTurnStarted to recover from accumulated debt.
|
||||||
|
*/
|
||||||
|
const MAX_BLOCKED_PENDING = 3;
|
||||||
|
|
||||||
export function markTurnStarted(channelId: string, agentId: string): void {
|
export function markTurnStarted(channelId: string, agentId: string): void {
|
||||||
pendingTurns().add(`${channelId}:${agentId}`);
|
pendingTurns().add(`${channelId}:${agentId}`);
|
||||||
|
// Cap existing blocked-pending at MAX to recover from accumulated debt
|
||||||
|
// (can occur when many messages arrive during a long non-speaker period).
|
||||||
|
const bpc = blockedPendingCounts();
|
||||||
|
const key = `${channelId}:${agentId}`;
|
||||||
|
const current = bpc.get(key) ?? 0;
|
||||||
|
if (current > MAX_BLOCKED_PENDING) bpc.set(key, MAX_BLOCKED_PENDING);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isTurnPending(channelId: string, agentId: string): boolean {
|
export function isTurnPending(channelId: string, agentId: string): boolean {
|
||||||
@@ -74,10 +88,12 @@ export function clearTurnPending(channelId: string, agentId: string): void {
|
|||||||
* causing false empty-turn detection. We count them and skip one per agent_end
|
* causing false empty-turn detection. We count them and skip one per agent_end
|
||||||
* until the count reaches zero, at which point the next agent_end is real.
|
* until the count reaches zero, at which point the next agent_end is real.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function incrementBlockedPending(channelId: string, agentId: string): void {
|
export function incrementBlockedPending(channelId: string, agentId: string): void {
|
||||||
const bpc = blockedPendingCounts();
|
const bpc = blockedPendingCounts();
|
||||||
const key = `${channelId}:${agentId}`;
|
const key = `${channelId}:${agentId}`;
|
||||||
bpc.set(key, (bpc.get(key) ?? 0) + 1);
|
const current = bpc.get(key) ?? 0;
|
||||||
|
if (current < MAX_BLOCKED_PENDING) bpc.set(key, current + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns true (and decrements) if this agent_end should be treated as a stale blocked completion. */
|
/** Returns true (and decrements) if this agent_end should be treated as a stale blocked completion. */
|
||||||
|
|||||||
Reference in New Issue
Block a user