/// <summary> /// Starts processing. /// </summary> public Task OpenAsync(PartitionContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } _logger.LogInformation($"Processor starting. {GetPartitionContextLogInfo(context)}"); // Configure the retry policy for use. _policyAsync = Policy .HandleResult <FunctionResult>(fr => !fr.Succeeded) .WaitAndRetryForeverAsync( (count, ctx) => { if (OverrideRetryTimespan.HasValue) { return(OverrideRetryTimespan.Value); } if (count > 16) // 2^16 is 65,536 which is the biggest allowed within our 1 day (86,400s) constraint therefore no need to calculate. { return(_options.MaxRetryTimespan); } else { // Use a jitterer to randomise the retrys to limit retry concurrency across the underlying threads (key for the early retries). var ts = TimeSpan.FromSeconds(Math.Pow(2, count)) + TimeSpan.FromMilliseconds(jitterer.Next(0, 100)); return(ts < _options.MaxRetryTimespan ? ts : _options.MaxRetryTimespan); } }, async(dr, count, timespan, ctx) => { var isPoisoned = _currPoisonAction == PoisonMessageAction.PoisonRetry || count >= _options.LogPoisonMessageAfterRetryCount; var msg = $"Failure retry{(isPoisoned ? " (Poisoned)" : "")} in {timespan.TotalSeconds}s (attempt {count}) {GetEventDataLogInfo(context, _currEventData!)}."; switch (count) { case var val when val == _options.LogPoisonMessageAfterRetryCount: // Set the poison message now that we have (possibly) attempted enough times that it may not be transient in nature and some needs to be alerted. await _poisonOrchestrator !.SetAsync(_currEventData !, dr.Result.Exception).ConfigureAwait(false); _currPoisonAction = PoisonMessageAction.PoisonRetry; _logger.LogError(dr.Result.Exception, msg); break; case var val when val > _options.LogPoisonMessageAfterRetryCount: // Keep logging advising the error is still in play. _logger.LogError(dr.Result.Exception, msg); break; default: // It could be a transient error, so report as a warning until identified as poison. if (isPoisoned) { _logger.LogError(dr.Result.Exception, msg); } else { _logger.LogWarning(dr.Result.Exception, msg); } break; } }); // Instantiate the poison message orchestration. _poisonOrchestrator = PoisonMessagePersistence.Create(new PoisonMessageCreatePersistenceArgs { Config = _config, Context = context, Logger = _logger, Options = _options }); return(Task.CompletedTask); }