private async Task ResendExpiredMessagesAsync(CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested && _channel.IsEstablished()) { try { await Task.Delay(_resendWindow, cancellationToken); var expiredMessageKeys = await _messageStorage.GetMessagesToResendKeysAsync(_channelKey, DateTimeOffset.UtcNow, cancellationToken); foreach (var expiredMessageKey in expiredMessageKeys) { cancellationToken.ThrowIfCancellationRequested(); var expiredMessage = await _messageStorage.RemoveAsync(_channelKey, expiredMessageKey, cancellationToken); if (expiredMessage == null) { continue; // It may be already removed } var resendCount = GetMessageResendCount(expiredMessage); // Check the message resend limit if (resendCount < _maxResendCount) { // Set the metadata key resendCount++; SetMessageResendCount(expiredMessage, resendCount); try { await _channel.SendMessageAsync(expiredMessage, cancellationToken); } catch (Exception ex) { if (_resendExceptionHandler != null) { await _resendExceptionHandler(ex, _channel, expiredMessage); } else { Trace.TraceError( "Error resending a message with id {0} on channel {1}: {2}", expiredMessage.Id, _channel.SessionId, ex); } // Create a new CTS because the exception can be caused by the cancellation of the method token using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); try { // If any error occurs when resending the message, put the expired message // back into the storage before throwing the exception. await _messageStorage.AddAsync( _channelKey, expiredMessageKey, expiredMessage, DateTimeOffset.UtcNow.Add(_resendWindow), cts.Token); } catch (OperationCanceledException) { } throw; } } else { await _deadMessageHandler.HandleDeadMessageAsync(expiredMessage, _channel, cancellationToken); } } } catch (ObjectDisposedException) when(_disposing) { break; } catch (OperationCanceledException) when(cancellationToken.IsCancellationRequested) { break; } catch (Exception ex) { if (_resendExceptionHandler != null) { await _resendExceptionHandler(ex, _channel, null); } else { Trace.TraceError( "An unhandled exception occurred on ResendMessagesChannelModule on channel {0}: {1}", _channel.SessionId, ex); } } } }
private async Task ResendExpiredMessagesAsync(CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested && _channel.State == SessionState.Established && _channel.Transport.IsConnected) { try { await Task.Delay(_resendWindow, cancellationToken); var expiredMessageKeys = await _messageStorage.GetMessagesToResendKeysAsync(_channelKey, DateTimeOffset.UtcNow, cancellationToken); foreach (var expiredMessageKey in expiredMessageKeys) { cancellationToken.ThrowIfCancellationRequested(); var expiredMessage = await _messageStorage.RemoveAsync(_channelKey, expiredMessageKey, cancellationToken); if (expiredMessage == null) { continue; // It may be already removed } var resendCount = GetMessageResendCount(expiredMessage); // Check the message resend limit if (resendCount < _maxResendCount) { // Set the metadata key resendCount++; SetMessageResendCount(expiredMessage, resendCount); try { await _channel.SendMessageAsync(expiredMessage, cancellationToken); } catch { // Create a new CTS because the exception can be caused by the cancellation of the method token using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5))) { try { // If any error occurs when resending the message, put the expired message // back into the storage before throwing the exception. await _messageStorage.AddAsync(_channelKey, expiredMessageKey, expiredMessage, DateTimeOffset.UtcNow, cts.Token); } catch (OperationCanceledException) { } throw; } } } else { await _deadMessageHandler.HandleDeadMessageAsync(expiredMessage, _channel, cancellationToken); } } } catch (OperationCanceledException) when(cancellationToken.IsCancellationRequested) { break; } catch (Exception ex) { Trace.TraceError(ex.ToString()); if (_channel.State != SessionState.Established || !_channel.Transport.IsConnected) { break; } throw; } } }