private async Task <long> StreamEventsToProjections(ExclusiveEventStoreCatchupQuery query) { long eventsProcessedOutOfBatch = 0; foreach (var storedEvent in query.Events) { eventsProcessedOutOfBatch++; IncludeReadModelsNeeding(storedEvent); if (cancellationDisposable.IsDisposed) { break; } IEvent @event = null; var now = Clock.Now(); try { @event = await UpdateProjectorsAndCursors( query, storedEvent, eventsProcessedOutOfBatch, now); } catch (Exception ex) { var error = @event == null ? SerializationError(ex, storedEvent) : new Domain.EventHandlingError(ex, @event: @event); ReadModelUpdate.ReportFailure( error, createReadModelDbContext); } var status = new ReadModelCatchupStatus { BatchCount = query.BatchMatchedEventCount, NumberOfEventsProcessed = eventsProcessedOutOfBatch, CurrentEventId = storedEvent.Id, EventTimestamp = storedEvent.Timestamp, StatusTimeStamp = now, CatchupName = Name }; if (status.IsEndOfBatch) { // reset the re-entrancy flag running = 0; query.Dispose(); } ReportStatus(status); } return(eventsProcessedOutOfBatch); }
/// <summary> /// Reports event handling errors via the specified database. /// </summary> /// <param name="bus">The bus.</param> /// <param name="createDbContext">The database.</param> /// <returns></returns> public static IDisposable ReportErrorsToDatabase(this IEventBus bus, Func <DbContext> createDbContext) => bus.Errors.Subscribe(e => ReadModelUpdate.ReportFailure(e, createDbContext));
private async Task <long> StreamEventsToProjections(ExclusiveEventStoreCatchupQuery query) { long eventsProcessed = 0; foreach (var storedEvent in query.Events) { eventsProcessed++; IncludeReadModelsNeeding(storedEvent); if (cancellationDisposable.IsDisposed) { break; } IEvent @event = null; var now = Clock.Now(); try { // update projectors @event = storedEvent.ToDomainEvent(); if (@event != null) { using (var work = CreateUnitOfWork(@event)) { await bus.PublishAsync(@event); var infos = work.Resource <DbContext>().Set <ReadModelInfo>(); subscribedReadModelInfos.ForEach(i => { var eventsRemaining = query.ExpectedNumberOfEvents - eventsProcessed; infos.Attach(i); i.LastUpdated = now; i.CurrentAsOfEventId = storedEvent.Id; i.LatencyInMilliseconds = (now - @event.Timestamp).TotalMilliseconds; i.BatchRemainingEvents = eventsRemaining; if (eventsProcessed == 1) { i.BatchStartTime = now; i.BatchTotalEvents = query.ExpectedNumberOfEvents; } if (i.InitialCatchupStartTime == null) { i.InitialCatchupStartTime = now; i.InitialCatchupEvents = query.ExpectedNumberOfEvents; } if (eventsRemaining == 0 && i.InitialCatchupEndTime == null) { i.InitialCatchupEndTime = now; } }); work.VoteCommit(); } } else { throw new SerializationException(string.Format( "Deserialization: Event type '{0}.{1}' not found", storedEvent.StreamName, storedEvent.Type)); } } catch (Exception ex) { var error = @event == null ? SerializationError(ex, storedEvent) : new Domain.EventHandlingError(ex, @event: @event); ReadModelUpdate.ReportFailure( error, () => CreateReadModelDbContext()); } var status = new ReadModelCatchupStatus { BatchCount = query.ExpectedNumberOfEvents, NumberOfEventsProcessed = eventsProcessed, CurrentEventId = storedEvent.Id, EventTimestamp = storedEvent.Timestamp, StatusTimeStamp = now, CatchupName = Name }; if (status.IsEndOfBatch) { // reset the re-entrancy flag running = 0; query.Dispose(); } ReportStatus(status); } return(eventsProcessed); }
/// <summary> /// Reports event handling errors via the specified database. /// </summary> /// <param name="bus">The bus.</param> /// <param name="db">The database.</param> /// <returns></returns> public static IDisposable ReportErrorsToDatabase(this IEventBus bus, Func <DbContext> db) { return(bus.Errors.Subscribe(e => ReadModelUpdate.ReportFailure(e, db))); }