Exemple #1
0
        private void InitializeReadModelInfo()
        {
            using (var db = createReadModelDbContext())
            {
                EnsureLockResourceNameIsInitialized(db);

                var existingReadModelInfoNames = GetProjectorNames();
                var existingReadModelInfos     = db.Set <ReadModelInfo>()
                                                 .OrderBy(i => i.Name)
                                                 .Where(i => existingReadModelInfoNames.Contains(i.Name))
                                                 .ToList();
                unsubscribedReadModelInfos = new List <ReadModelInfo>(existingReadModelInfos);
                subscribedReadModelInfos   = new List <ReadModelInfo>();

                // create ReadModelInfo entries for any projectors that don't already have them
                foreach (var projector in projectors.Where(p => !unsubscribedReadModelInfos.Select(i => i.Name).Contains(ReadModelInfo.NameForProjector(p))))
                {
                    var readModelInfo = new ReadModelInfo
                    {
                        Name = ReadModelInfo.NameForProjector(projector)
                    };
                    db.Set <ReadModelInfo>().Add(readModelInfo);
                    unsubscribedReadModelInfos.Add(readModelInfo);
                }
                db.SaveChanges();
            }
        }
Exemple #2
0
        internal static void ReportFailure(
            Domain.EventHandlingError error,
            Func <DbContext> createDbContext)
        {
            // add an EventHandlingError entry as well
            EventHandlingError sqlError = CreateEventHandlingError((dynamic)error);

            var errorText = new
            {
                error.Exception,
                Event = sqlError.SerializedEvent
            }.ToJson();

            log.Write(() => errorText);

            using (var transaction = new TransactionScope(TransactionScopeOption.Suppress))
                using (var db = createDbContext())
                {
                    var dbSet = db.Set <ReadModelInfo>();

                    var handler = error.Handler;

                    string readModelInfoName = null;

                    if (handler != null)
                    {
                        // update the affected ReadModelInfo
                        readModelInfoName = ReadModelInfo.NameForProjector(handler);

                        var readModelInfo = dbSet.SingleOrDefault(i => i.Name == readModelInfoName);
                        if (readModelInfo == null)
                        {
                            readModelInfo = new ReadModelInfo {
                                Name = readModelInfoName
                            };
                            dbSet.Add(readModelInfo);
                        }

                        readModelInfo.Error           = errorText;
                        readModelInfo.FailedOnEventId = sqlError.OriginalId;
                    }

                    sqlError.Error   = error.Exception.ToJson();
                    sqlError.Handler = readModelInfoName;
                    db.Set <EventHandlingError>().Add(sqlError);

                    db.SaveChanges();
                    transaction.Complete();
                }
        }
        private void EnsureInitialized()
        {
            if (subscribedReadModelInfos != null)
            {
                return;
            }

            // figure out which event types we will need to query
            matchEvents = projectors.SelectMany(p => p.MatchesEvents())
                          .Distinct()
                          .Select(m =>
            {
                // TODO: (EnsureInitialized) optimize this by figuring out how to query SteamName LIKE 'Scheduled:%'
                if (m.Type == "Scheduled")
                {
                    return(new MatchEvent(m.StreamName, "*"));
                }
                return(m);
            })
                          .ToArray();

            Debug.WriteLine(string.Format("Catchup {0}: Subscribing to event types: {1}", Name, matchEvents.Select(m => m.ToString()).ToJson()));

            using (var db = CreateReadModelDbContext())
            {
                EnsureLockResourceNameIsInitialized(db);

                var existingReadModelInfoNames = GetProjectorNames();
                var existingReadModelInfos     = db.Set <ReadModelInfo>()
                                                 .OrderBy(i => i.Name)
                                                 .Where(i => existingReadModelInfoNames.Contains(i.Name))
                                                 .ToList();
                unsubscribedReadModelInfos = new List <ReadModelInfo>(existingReadModelInfos);
                subscribedReadModelInfos   = new List <ReadModelInfo>();

                // create ReadModelInfo entries for any projectors that don't already have them
                foreach (var projector in projectors.Where(p => !unsubscribedReadModelInfos.Select(i => i.Name).Contains(ReadModelInfo.NameForProjector(p))))
                {
                    var readModelInfo = new ReadModelInfo
                    {
                        Name = ReadModelInfo.NameForProjector(projector)
                    };
                    db.Set <ReadModelInfo>().Add(readModelInfo);
                    unsubscribedReadModelInfos.Add(readModelInfo);
                }
                db.SaveChanges();
            }
        }
Exemple #4
0
 private void IncludeReadModelsNeeding(StorableEvent storedEvent)
 {
     if (unsubscribedReadModelInfos.Count > 0)
     {
         foreach (var readmodelInfo in unsubscribedReadModelInfos.ToArray())
         {
             if (storedEvent.Id >= readmodelInfo.CurrentAsOfEventId + 1)
             {
                 var handler = projectors.Single(p => ReadModelInfo.NameForProjector(p) == readmodelInfo.Name);
                 disposables.Add(bus.Subscribe(handler));
                 unsubscribedReadModelInfos.Remove(readmodelInfo);
                 subscribedReadModelInfos.Add(readmodelInfo);
             }
         }
     }
 }
        internal static void ReportFailure(
            Domain.EventHandlingError error,
            Func <DbContext> createDbContext)
        {
            // add an EventHandlingError entry as well
            EventHandlingError sqlError = CreateEventHandlingError((dynamic)error);

            log.Write(() => new { error.Exception, sqlError.SerializedEvent });

            using (var db = createDbContext())
            {
                var dbSet = db.Set <ReadModelInfo>();

                var handler = error.Handler;

                string readModelInfoName = null;

                var exceptionJson = error.Exception.ToDiagnosticJson();
                if (handler != null)
                {
                    // update the affected ReadModelInfo
                    readModelInfoName = ReadModelInfo.NameForProjector(handler);

                    var readModelInfo = dbSet.SingleOrDefault(i => i.Name == readModelInfoName);
                    if (readModelInfo == null)
                    {
                        readModelInfo = new ReadModelInfo {
                            Name = readModelInfoName
                        };
                        dbSet.Add(readModelInfo);
                    }

                    readModelInfo.LastError       = exceptionJson;
                    readModelInfo.FailedOnEventId = sqlError.EventId;
                }

                sqlError.Error   = $"{Environment.MachineName}:  {exceptionJson}";
                sqlError.Handler = readModelInfoName;
                db.Set <EventHandlingError>().Add(sqlError);

                db.SaveChanges();
            }
        }
        private long StreamEventsToProjections(ExclusiveEventStoreCatchupQuery query)
        {
            long eventsProcessed = 0;

            foreach (var storedEvent in query.Events)
            {
                eventsProcessed++;

                if (unsubscribedReadModelInfos.Count > 0)
                {
                    foreach (var readmodelInfo in unsubscribedReadModelInfos.ToArray())
                    {
                        if (storedEvent.Id >= readmodelInfo.CurrentAsOfEventId + 1)
                        {
                            var handler = projectors.Single(p => ReadModelInfo.NameForProjector(p) == readmodelInfo.Name);
                            disposables.Add(bus.Subscribe(handler));
                            unsubscribedReadModelInfos.Remove(readmodelInfo);
                            subscribedReadModelInfos.Add(readmodelInfo);
                        }
                    }
                }

                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))
                        {
                            bus.PublishAsync(@event).Wait();

                            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);
        }