Ayende posted a modification to Davy Brion's circuit breaker, wherein he changed the timeout resolution to a lazy model.
private readonly DateTime expiry;
public OpenState(CircuitBreaker outer)
: base(outer)
{
expiry = DateTime.UtcNow + outer.timeout;
}
public override void ProtectedCodeIsAboutToBeCalled()
{
if(DateTime.UtcNow < expiry)
throw new OpenCircuitException();
outer.MoveToHalfOpenState();
}
However, the constructor can fail because a TimeSpan
can quickly overflow the maximum value of a DateTime
. For example, when the circuit breaker’s timeout is the maximum value of a TimeSpan.
System.ArgumentOutOfRangeException was caught
Message="The added or subtracted value results in an un-representable DateTime."
...
at System.DateTime.op_Addition(DateTime d, TimeSpan t)
How do we avoid this problem and maintain the expected behavior?
Determine if the timeout is greater than the remainder of the maximum value of a DateTime
and the current DateTime
. A maximum TimeSpan
usually indicates a functionally infinite timeout (making this a "one-time" circuit breaker).
public OpenState(CircuitBreaker outer)
: base(outer)
{
DateTime now = DateTime.UtcNow;
expiry = outer.Timeout > (DateTime.MaxValue - now)
? DateTime.MaxValue
: now + outer.Timeout;
}