private async Task DeadLetterMessage(T vstsMessage, IServiceBusMessage message, IDictionary <string, string> eventProperties, string errorMessage, CancellationToken cancellationToken) { if (!eventProperties.ContainsKey(VstsMessageConstants.ErrorTypePropertyName)) { eventProperties[VstsMessageConstants.ErrorTypePropertyName] = errorMessage; } await this.TryFailOrchestrationPlan(vstsMessage, cancellationToken).ConfigureAwait(false); await clientLogger.LogError("DeadLetterMessage", errorMessage, eventProperties, cancellationToken).ConfigureAwait(false); await this.queueClient.DeadLetterAsync(message.GetLockToken()).ConfigureAwait(false); }
public async Task ReceiveAsync(IServiceBusMessage message, CancellationToken cancellationToken) { // setup basic message properties var messageStopwatch = Stopwatch.StartNew(); var eventProperties = ExtractServiceBusMessageProperties(message); Exception exception = null; T vstsMessage = null; try { // validate & extract string errorMessage; if (!ExtractMessage(message, out vstsMessage, out errorMessage)) { await this.DeadLetterMessage(null, message, eventProperties, errorMessage, cancellationToken).ConfigureAwait(false); await this.StopTimer("MessageExtractionFailed", messageStopwatch, eventProperties, cancellationToken).ConfigureAwait(false); return; } // merge vsts properties foreach (var property in vstsMessage.GetMessageProperties()) { eventProperties[property.Key] = property.Value; } // process message await this.ProcessMessage(message, this.scheduleHandler, cancellationToken, vstsMessage, eventProperties).ConfigureAwait(false); await this.queueClient.CompleteAsync(message.GetLockToken()).ConfigureAwait(false); await this.StopTimer("MessageProcessingSucceeded", messageStopwatch, eventProperties, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { exception = ex; } // c#6.0 allows await inside catch but this code is not 6.0 yet :-( if (exception != null) { await this.StopTimer("MessageProcessingFailed", messageStopwatch, eventProperties, cancellationToken).ConfigureAwait(false); await this.AbandonOrDeadLetterMessage(vstsMessage, message, exception, eventProperties, cancellationToken).ConfigureAwait(false); } }
private async Task DelayedAbandon(IServiceBusMessage message, int attempt, Exception exception, IDictionary <string, string> eventProperties, CancellationToken cancellationToken) { // exponential backoff var delayMsecs = this.settings.AbandonDelayMsecs + (1000 * (int)(Math.Pow(2, Math.Max(0, attempt - 1)) - 1)); delayMsecs = Math.Min(delayMsecs, this.settings.MaxAbandonDelayMsecs); var abandoningMessageDueToException = string.Format("Abandoning message due to exception in [{0}]ms", delayMsecs); await clientLogger.LogException(exception, "MessageProcessingException", abandoningMessageDueToException, eventProperties, cancellationToken).ConfigureAwait(false); while (delayMsecs > 0) { // await message.RenewLockAsync().ConfigureAwait(false); var delay = settings.LockRefreshDelayMsecs == 0 ? 10 : settings.LockRefreshDelayMsecs; await Task.Delay(delay, cancellationToken); delayMsecs -= delay; cancellationToken.ThrowIfCancellationRequested(); } await this.queueClient.AbandonAsync(message.GetLockToken()).ConfigureAwait(false); }