/// <summary> /// Initializes a new <see cref="MessageJournalEntry"/> /// </summary> /// <param name="category">The category of journaled message (e.g. sent, received, published)</param> /// <param name="position">The position of the message in the journal</param> /// <param name="timestamp">The timestamp associated with the journal entry</param> /// <param name="data">The message</param> public MessageJournalEntry(MessageJournalCategory category, MessageJournalPosition position, DateTime timestamp, Message data) { Category = category; Position = position ?? throw new ArgumentNullException(nameof(position)); Timestamp = timestamp; Data = data ?? throw new ArgumentNullException(nameof(data)); }
/// <summary> /// Consumes entries from the message journal starting at the specified <paramref name="start"/> /// position /// </summary> /// <param name="start">The position of the first journal entry to consume</param> /// <param name="cancellationToken">(Optional) A cancellation token that can be used by the /// caller to interrupt the message consumption process</param> /// <returns>Returns a task that completes when the end of the journal is reached, when an /// exception is thrown, or when cancellation is requested, depending on the options /// specified in the constructor</returns> private async Task ConsumeAsync(MessageJournalPosition start, CancellationToken cancellationToken = default(CancellationToken)) { var count = 0L; var bus = await _bus; var current = start ?? await _messageJournal.GetBeginningOfJournal(cancellationToken); try { while (!cancellationToken.IsCancellationRequested) { var readResult = await ReadNext(cancellationToken, current); if (readResult != null) { count = await HandleMessageJournalEntries(count, readResult, bus, cancellationToken); current = readResult.Next; if (readResult.EndOfJournal && _haltAtEndOfJournal) { return; } } await Task.Delay(_pollingInterval, cancellationToken); } } catch (OperationCanceledException) { } }
/// <summary> /// Consumes entries from the message journal starting at the specified <paramref name="start"/> /// position /// </summary> /// <param name="start">The position of the first journal entry to consume</param> /// <param name="cancellationToken">(Optional) A cancellation token that can be used by the /// caller to interrupt the message consumption process</param> /// <returns>Returns a task that completes when the end of the journal is reached, when an /// exception is thrown, or when cancellation is requested, depending on the options /// specified in the constructor</returns> public Task Consume(MessageJournalPosition start, CancellationToken cancellationToken = default(CancellationToken)) { return(ConsumeAsync(start, cancellationToken) .GetCompletionSource(cancellationToken) .Task); }
/// <summary> /// Initializes a new <see cref="MessageJournalReadResult"/> /// </summary> /// <param name="start">The position at which the read started</param> /// <param name="next">The next position to read from</param> /// <param name="endOfJournal">Whether the end of the journal was reached during the read operation</param> /// <param name="messages">The journaled messages that were read</param> public MessageJournalReadResult(MessageJournalPosition start, MessageJournalPosition next, bool endOfJournal, IEnumerable <MessageJournalEntry> messages) { Start = start ?? throw new ArgumentNullException(nameof(start)); Next = next ?? throw new ArgumentNullException(nameof(next)); EndOfJournal = endOfJournal; _entries = (messages ?? Enumerable.Empty <MessageJournalEntry>()).ToList(); }
/// <summary> /// Initialies a new <see cref="MessageJournalConsumerProgress"/> /// </summary> /// <param name="count">The number of entries consumed</param> /// <param name="timestamp">The timestamp of the last entry that was read</param> /// <param name="current">The position of the message journal entry that was just consumed</param> /// <param name="next">The position of the next entry that will be read</param> /// <param name="endOfJournal">Whether the entry that was just consumed is the last one in the /// journal as of the last read</param> public MessageJournalConsumerProgress(long count, DateTime timestamp, MessageJournalPosition current, MessageJournalPosition next, bool endOfJournal) { Count = count; Timestamp = timestamp; Current = current ?? throw new ArgumentNullException(nameof(current)); Next = next ?? throw new ArgumentNullException(nameof(next)); EndOfJournal = endOfJournal; }
private async Task HandleMessageJournalEntry(IBus bus, CancellationToken cancellationToken, MessageJournalEntry current, MessageJournalPosition next, long count) { try { // Throws MessageNotAcknowledgedException if there are handling rules that apply to // the message but the message is not acknowledged (automatically or otherwise) await bus.HandleMessage(current.Data, Thread.CurrentPrincipal, cancellationToken); } catch (OperationCanceledException) { throw; } catch (MessageNotAcknowledgedException ex) { _diagnosticService.Emit(new DiagnosticEventBuilder(this, DiagnosticEventType.MessageNotAcknowledged) { Message = current.Data, Detail = "Message was not acknowledged by any handlers", Exception = ex }.Build()); if (_rethrowExceptions) { throw; } } catch (Exception ex) { _diagnosticService.Emit(new DiagnosticEventBuilder(this, DiagnosticEventType.UnhandledException) { Message = current.Data, Detail = "Unhandled exception thrown by one or more message handlers", Exception = ex }.Build()); if (_rethrowExceptions) { throw; } } finally { if (_progress != null) { var progressReport = new MessageJournalConsumerProgress( count, current.Timestamp, current.Position, next, false); _progress.Report(progressReport); } } }
private async Task <MessageJournalReadResult> ReadNext(CancellationToken cancellationToken, MessageJournalPosition current) { MessageJournalReadResult readResult = null; try { readResult = await _messageJournal.Read(current, _batchSize, _filter, cancellationToken); } catch (OperationCanceledException) { throw; } catch (Exception ex) { _diagnosticService.Emit(new DiagnosticEventBuilder(this, DiagnosticEventType.UnhandledException) { Detail = "Error reading message journal", Exception = ex }.Build()); if (_rethrowExceptions) { throw; } } return(readResult); }
public Task <MessageJournalReadResult> Read(MessageJournalPosition start, int count, MessageJournalFilter filter = null, CancellationToken cancellationToken = new CancellationToken()) { return(_inner.Read(start, count, filter, cancellationToken)); }