internal async Task SpinOnce(CancellationToken cancellationToken)
{
if (NextRetrieval > currentTimeProvider() || cancellationToken.IsCancellationRequested)
{
return;
}
Logger.DebugFormat("Polling for timeouts at {0}.", currentTimeProvider());
var timeoutChunk = await timeoutsFetcher.GetNextChunk(startSlice).ConfigureAwait(false);
foreach (var timeoutData in timeoutChunk.DueTimeouts)
{
if (cancellationToken.IsCancellationRequested)
{
return;
}
if (startSlice < timeoutData.DueTime)
{
startSlice = timeoutData.DueTime;
}
var dispatchRequest = ControlMessageFactory.Create(MessageIntentEnum.Send);
dispatchRequest.Headers["Timeout.Id"] = timeoutData.Id;
var transportOperation = new TransportOperation(dispatchRequest, new UnicastAddressTag(dispatcherAddress));
await dispatcher.Dispatch(new TransportOperations(transportOperation), new TransportTransaction(), new ContextBag()).ConfigureAwait(false);
}
lock (lockObject)
{
var nextTimeToQuery = timeoutChunk.NextTimeToQuery;
// we cap the next retrieval to max 1 minute this will make sure that we trip the circuit breaker if we
// loose connectivity to our storage. This will also make sure that timeouts added (during migration) direct to storage
// will be picked up after at most 1 minute
var maxNextRetrieval = currentTimeProvider() + MaxNextRetrievalDelay;
NextRetrieval = nextTimeToQuery > maxNextRetrieval ? maxNextRetrieval : nextTimeToQuery;
Logger.DebugFormat("Polling next retrieval is at {0}.", NextRetrieval.ToLocalTime());
}
circuitBreaker.Success();
}