connor4312/cockatiel
CircuitBreakerPolicy HalfOpen state drops AbortSignal in recursive execute()
Summary
Context: The CircuitBreakerPolicy’s
executemethod handles calls that arrive during the HalfOpen state by waiting for the half-open test to complete, then recursively callingexecuteto process the queued call.Bug: When the circuit is in HalfOpen state and a second call arrives with an abort signal, the recursive
execute()call does not pass the signal parameter.Actual vs. expected: The abort signal is lost and replaced with
neverAbortedSignal(the default parameter), so the executed function receives a non-abortable signal instead of the caller’s signal.Impact: Functions cannot respond to cancellation requests, breaking the AbortSignal cancellation contract and potentially causing operations to run longer than intended or waste resources on cancelled operations.
Code with bug
From src/CircuitBreakerPolicy.ts:
Logical proof
Method signature shows
signalhas a default:
During HalfOpen, a call arrives as
execute(fn, myAbortSignal); after waiting for the half-open test, code recurses withthis.execute(fn)(nosignal).Parameter binding uses the default for the missing second arg, so
signal = neverAbortedSignal.Result:
Therefore the original AbortSignal is lost and the function cannot observe or react to caller cancellation.
Recommended fix
Change:
To: