예제 #1
0
        async Task <ProjectionStream> LoadProjectionStreamAsync(Type projectionType, IBlobId projectionId)
        {
            string projectionName = projectionType.GetContractId();

            ReadResult <ProjectionVersions> result = GetProjectionVersions(projectionName);

            if (result.IsSuccess)
            {
                ProjectionVersion liveVersion = result.Data.GetLive();
                if (liveVersion is null)
                {
                    log.Warn(() => $"Unable to find projection `live` version. ProjectionId:{projectionId} ProjectionName:{projectionName} ProjectionType:{projectionType.Name}");
                    return(ProjectionStream.Empty());
                }

                ISnapshot snapshot = null;
                if (projectionType.IsSnapshotable())
                {
                    snapshot = snapshotStore.Load(projectionName, projectionId, liveVersion);
                }
                else
                {
                    snapshot = new NoSnapshot(projectionId, projectionName);
                }

                ProjectionStream stream = await LoadProjectionStreamAsync(projectionType, liveVersion, projectionId, snapshot);

                return(stream);
            }

            return(ProjectionStream.Empty());
        }
예제 #2
0
        ProjectionStream LoadProjectionStream(Type projectionType, IBlobId projectionId)
        {
            string projectionName = projectionType.GetContractId();

            ReadResult <ProjectionVersions> result = GetProjectionVersions(projectionName);

            if (result.IsSuccess)
            {
                ProjectionVersion liveVersion = result.Data.GetLive();
                if (liveVersion is null)
                {
                    log.Warn(() => $"Unable to find projection `live` version. ProjectionId:{projectionId} ProjectionName:{projectionName} ProjectionType:{projectionType.Name}{Environment.NewLine}AvailableVersions:{Environment.NewLine}{result.Data.ToString()}");
                    return(ProjectionStream.Empty());
                }

                ISnapshot snapshot = null;
                if (projectionType.IsSnapshotable())
                {
                    snapshot = snapshotStore.Load(projectionName, projectionId, liveVersion);
                }
                else
                {
                    snapshot = new NoSnapshot(projectionId, projectionName);
                }

                return(LoadProjectionStream(projectionType, liveVersion, projectionId, snapshot));
            }

            return(ProjectionStream.Empty());
        }
예제 #3
0
파일: Snapshot.cs 프로젝트: lulzzz/Cronus
 public Snapshot(IBlobId id, string projectionContractId, object state, int revision)
 {
     Id = id;
     ProjectionContractId = projectionContractId;
     State    = state;
     Revision = revision;
 }
예제 #4
0
        public IProjectionGetResult <T> Get <T>(IBlobId projectionId) where T : IProjectionDefinition
        {
            if (ReferenceEquals(null, projectionId))
            {
                throw new ArgumentNullException(nameof(projectionId));
            }

            Type   projectionType = typeof(T);
            string contractId     = projectionType.GetContractId();

            try
            {
                ProjectionVersion liveVersion = GetProjectionVersions(contractId).GetLive();
                if (ReferenceEquals(null, liveVersion))
                {
                    log.Warn(() => $"Unable to find `live` version for projection with contract id {contractId} and name {projectionType.Name}");
                    return(new ProjectionGetResult <T>(default(T)));
                }

                ISnapshot                snapshot    = snapshotStore.Load(contractId, projectionId, liveVersion);
                ProjectionStream         stream      = LoadProjectionStream(projectionType, liveVersion, projectionId, snapshot);
                IProjectionGetResult <T> queryResult = stream.RestoreFromHistory <T>();

                return(queryResult);
            }
            catch (Exception ex)
            {
                log.ErrorException($"Unable to load projection. ProjectionId:{projectionId} ProjectionContractId:{contractId} ProjectionName:{projectionType.Name}", ex);
                return(new ProjectionGetResult <T>(default(T)));
            }
        }
예제 #5
0
        public async Task <ReadResult <IProjectionDefinition> > GetAsync(IBlobId projectionId, Type projectionType)
        {
            using (log.BeginScope(s => s
                                  .AddScope(Log.ProjectionName, projectionType.GetContractId())
                                  .AddScope(Log.ProjectionType, projectionType.Name)
                                  .AddScope(Log.ProjectionInstanceId, projectionId.RawId)))
            {
                if (ReferenceEquals(null, projectionId))
                {
                    throw new ArgumentNullException(nameof(projectionId));
                }

                try
                {
                    ProjectionStream stream = await LoadProjectionStreamAsync(projectionType, projectionId);

                    var readResult = new ReadResult <IProjectionDefinition>(await stream.RestoreFromHistoryAsync(projectionType).ConfigureAwait(false));
                    if (readResult.NotFound && log.IsDebugEnabled())
                    {
                        log.Debug(() => "Projection instance not found.");
                    }

                    return(readResult);
                }
                catch (Exception ex)
                {
                    log.ErrorException(ex, () => "Unable to load projection.");
                    return(ReadResult <IProjectionDefinition> .WithError(ex));
                }
            }
        }
예제 #6
0
 public Snapshot(IBlobId id, string projectionName, object state, int revision)
 {
     Id             = id;
     ProjectionName = projectionName;
     State          = state;
     Revision       = revision;
 }
예제 #7
0
 public ProjectionCommit(IBlobId projectionId, string contractId, IEvent @event, int snapshotMarker, EventOrigin eventOrigin, DateTime timeStamp)
 {
     ProjectionId   = projectionId;
     ContractId     = contractId;
     Event          = @event;
     SnapshotMarker = snapshotMarker;
     EventOrigin    = eventOrigin;
     TimeStamp      = timeStamp;
 }
예제 #8
0
 public ProjectionCommit(IBlobId projectionId, ProjectionVersion version, IEvent @event, int snapshotMarker, EventOrigin eventOrigin, DateTime timeStamp)
 {
     ProjectionId   = projectionId;
     ProjectionName = version.ProjectionName;
     Event          = @event;
     SnapshotMarker = snapshotMarker;
     EventOrigin    = eventOrigin;
     TimeStamp      = timeStamp;
     Version        = version;
 }
예제 #9
0
        public Task <ISnapshot> LoadAsync(string projectionName, IBlobId id, ProjectionVersion version)
        {
            if (snapshots.ContainsKey(version) == false)
            {
                return(Task.FromResult((ISnapshot) new NoSnapshot(id, projectionName)));
            }

            ISnapshot snapshot = snapshots[version].FirstOrDefault(x => x.ProjectionName == projectionName && x.Id == id);

            return(Task.FromResult(snapshot ?? new NoSnapshot(id, projectionName)));
        }
예제 #10
0
        public IProjectionGetResult <IProjectionDefinition> Get(IBlobId projectionId, Type projectionType)
        {
            if (ReferenceEquals(null, projectionId))
            {
                throw new ArgumentNullException(nameof(projectionId));
            }

            ProjectionStream stream = LoadProjectionStream(projectionType, projectionId);

            return(stream.RestoreFromHistory(projectionType));
        }
예제 #11
0
        public IProjectionGetResult <T> Get <T>(IBlobId projectionId) where T : IProjectionDefinition
        {
            if (ReferenceEquals(null, projectionId))
            {
                throw new ArgumentNullException(nameof(projectionId));
            }

            Type projectionType = typeof(T);

            ProjectionStream stream = LoadProjectionStream(projectionType, projectionId);

            return(stream.RestoreFromHistory <T>());
        }
예제 #12
0
        public async Task <ProjectionDto> ExploreAsync(IBlobId id, Type projectionType)
        {
            var result           = new ProjectionDto();
            var projectionResult = await projections.GetAsync(id, projectionType);

            if (projectionResult.IsSuccess)
            {
                result.Name  = projectionType.Name;
                result.State = projectionResult.Data.State;
            }

            return(result);
        }
 IEnumerable <IBlobId> IProjectionDefinition.GetProjectionIds(IEvent @event)
 {
     foreach (var subscriptionResolver in subscriptionResolvers[@event.GetType()])
     {
         IBlobId resolvedId = subscriptionResolver(@event);
         if (resolvedId is ContinueId)
         {
             continue;
         }
         if (ReferenceEquals(null, resolvedId))
         {
             continue;                                    //TODO LOG
         }
         yield return(resolvedId);
     }
 }
예제 #14
0
        public string Resolve(IBlobId id)
        {
            if (ReferenceEquals(null, id) == true)
            {
                throw new ArgumentNullException(nameof(id));
            }

            var tenant = string.Empty;

            if (TryResolve(id.RawId, out tenant))
            {
                return(tenant);
            }

            throw new NotSupportedException($"Unable to resolve tenant for id {id}");
        }
예제 #15
0
        public ReadResult <IProjectionDefinition> Get(IBlobId projectionId, Type projectionType)
        {
            if (ReferenceEquals(null, projectionId))
            {
                throw new ArgumentNullException(nameof(projectionId));
            }

            try
            {
                ProjectionStream stream = LoadProjectionStream(projectionType, projectionId);
                return(new ReadResult <IProjectionDefinition>(stream.RestoreFromHistory(projectionType)));
            }
            catch (Exception ex)
            {
                log.ErrorException($"Unable to load projection. {projectionType.Name}({projectionId})", ex);
                return(ReadResult <IProjectionDefinition> .WithError(ex));
            }
        }
예제 #16
0
        public ProjectionStream(IBlobId projectionId, IList <ProjectionCommit> commits, ISnapshot snapshot)
        {
            if (ReferenceEquals(null, projectionId) == true)
            {
                throw new ArgumentException(nameof(projectionId));
            }
            if (ReferenceEquals(null, commits) == true)
            {
                throw new ArgumentException(nameof(commits));
            }
            if (ReferenceEquals(null, snapshot) == true)
            {
                throw new ArgumentException(nameof(snapshot));
            }

            this.projectionId = projectionId;
            this.commits      = commits;
            this.snapshot     = snapshot;
        }
예제 #17
0
        public string Resolve(IMessage message)
        {
            var tenantPropertyMeta = message.GetType().GetProperty("Tenant", typeof(string));

            if (tenantPropertyMeta is null == false)
            {
                return((string)tenantPropertyMeta.GetValue(message));
            }

            var     idMeta = message.GetType().GetProperties().Where(p => typeof(IBlobId).IsAssignableFrom(p.PropertyType)).FirstOrDefault();
            IBlobId id     = idMeta?.GetValue(message) as IBlobId;

            if (id is null == false)
            {
                return(Resolve(id));
            }

            throw new NotSupportedException($"Unable to resolve tenant from {message}");
        }
예제 #18
0
        public ProjectionStream(IBlobId projectionId, List <ProjectionCommit> commits, Func <ISnapshot> getSnapshot)
        {
            if (ReferenceEquals(null, projectionId))
            {
                throw new ArgumentException(nameof(projectionId));
            }
            if (ReferenceEquals(null, commits))
            {
                throw new ArgumentException(nameof(commits));
            }
            if (ReferenceEquals(null, getSnapshot))
            {
                throw new ArgumentException(nameof(getSnapshot));
            }

            this.projectionId = projectionId;
            this.Commits      = commits;
            this.getSnapshot  = getSnapshot;
        }
예제 #19
0
        public ReadResult <T> Get <T>(IBlobId projectionId) where T : IProjectionDefinition
        {
            try
            {
                if (ReferenceEquals(null, projectionId))
                {
                    throw new ArgumentNullException(nameof(projectionId));
                }

                Type projectionType = typeof(T);

                ProjectionStream stream = LoadProjectionStream(projectionType, projectionId);
                return(new ReadResult <T>(stream.RestoreFromHistory <T>()));
            }
            catch (Exception ex)
            {
                log.ErrorException($"Unable to load projection. {typeof(T).Name}({projectionId})", ex);
                return(ReadResult <T> .WithError(ex));
            }
        }
예제 #20
0
        public IProjectionGetResult <T> Get <T>(IBlobId projectionId) where T : IProjectionDefinition
        {
            try
            {
                Type   projectionType = typeof(T);
                string contractId     = projectionType.GetContractId();

                ProjectionVersion liveVersion = GetProjectionVersions(contractId).GetLive();

                ISnapshot                snapshot    = snapshotStore.Load(contractId, projectionId, liveVersion);
                ProjectionStream         stream      = LoadProjectionStream(projectionType, liveVersion, projectionId, snapshot);
                IProjectionGetResult <T> queryResult = stream.RestoreFromHistory <T>();

                return(queryResult);
            }
            catch (Exception ex)
            {
                log.ErrorException(ex.Message, ex);
                return(new ProjectionGetResult <T>(default(T)));
            }
        }
        public async Task <ReadResult <T> > GetAsync <T>(IBlobId projectionId) where T : IProjectionDefinition
        {
            if (ReferenceEquals(null, projectionId))
            {
                throw new ArgumentNullException(nameof(projectionId));
            }

            try
            {
                Type projectionType = typeof(T);

                ProjectionStream stream = await LoadProjectionStreamAsync(projectionType, projectionId);

                return(new ReadResult <T>(stream.RestoreFromHistory <T>()));
            }
            catch (Exception ex)
            {
                log.ErrorException(ex, () => $"Unable to load projection. {typeof(T).Name}({projectionId})");
                return(ReadResult <T> .WithError(ex));
            }
        }
예제 #22
0
        ProjectionStream LoadProjectionStream(Type projectionType, IBlobId projectionId)
        {
            string projectionName = projectionType.GetContractId();

            try
            {
                ProjectionVersion liveVersion = GetProjectionVersions(projectionName).GetLive();
                if (ReferenceEquals(null, liveVersion))
                {
                    log.Warn(() => $"Unable to find `live` version for projection with contract id {projectionName} and name {projectionType.Name}");
                    return(ProjectionStream.Empty());
                }

                ISnapshot        snapshot = snapshotStore.Load(projectionName, projectionId, liveVersion);
                ProjectionStream stream   = LoadProjectionStream(projectionType, liveVersion, projectionId, snapshot);

                return(stream);
            }
            catch (Exception ex)
            {
                log.ErrorException($"Unable to load projection stream. ProjectionId:{projectionId} ProjectionContractId:{projectionName} ProjectionName:{projectionType.Name}", ex);
                return(ProjectionStream.Empty());
            }
        }
예제 #23
0
        public async Task <ProjectionDto> ExploreIncludingEventsAsync(IBlobId id, Type projectionType)
        {
            ProjectionDto result = await ExploreAsync(id, projectionType).ConfigureAwait(false);

            bool projectionHasState = result.State is null == false;

            if (projectionHasState)
            {
                ProjectionVersion liveVersion = await GetLiveVersion(projectionType);

                if (liveVersion is null == false)
                {
                    var commits = new List <ProjectionCommitDto>();
                    await foreach (var item in projectionStore.EnumerateProjectionAsync(liveVersion, id))
                    {
                        commits.Add(item.ToProjectionDto());
                    }

                    result.Commits = commits;
                }
            }

            return(result);
        }
예제 #24
0
파일: NoSnapshot.cs 프로젝트: virajs/Cronus
 public NoSnapshot(IBlobId id, string projectionName)
 {
     Id             = id;
     ProjectionName = projectionName;
 }
예제 #25
0
 public AggregateCommit(IBlobId aggregateId, int revision, List <IEvent> events) : this(aggregateId.RawId, revision, events)
 {
 }
예제 #26
0
        public async IAsyncEnumerable <ProjectionCommit> LoadAsync(ProjectionVersion version, IBlobId projectionId, int snapshotMarker)
        {
            if (projectionCommits.ContainsKey(version) == false)
            {
                yield break;
            }

            if (projectionCommits[version].ContainsKey(projectionId) == false)
            {
                yield break;
            }

            IEnumerable <ProjectionCommit> commits = projectionCommits[version][projectionId].Where(x => x.SnapshotMarker == snapshotMarker);

            foreach (var commit in commits)
            {
                yield return(commit);
            }
        }
        async Task <ProjectionStream> LoadProjectionStreamAsync(Type projectionType, ProjectionVersion version, IBlobId projectionId, ISnapshot snapshot)
        {
            Func <ISnapshot> loadSnapshot = () => snapshot;

            List <ProjectionCommit> projectionCommits = new List <ProjectionCommit>();
            int snapshotMarker = snapshot.Revision;

            while (true)
            {
                snapshotMarker++;

                IEnumerable <ProjectionCommit> loadedProjectionCommits = await projectionStore.LoadAsync(version, projectionId, snapshotMarker);

                List <ProjectionCommit> loadedCommits = loadedProjectionCommits.ToList();
                projectionCommits.AddRange(loadedCommits);

                if (projectionType.IsSnapshotable() && snapshotStrategy.ShouldCreateSnapshot(projectionCommits, snapshot.Revision))
                {
                    ProjectionStream checkpointStream = new ProjectionStream(projectionId, projectionCommits, loadSnapshot);
                    var       projectionState         = checkpointStream.RestoreFromHistory(projectionType).State;
                    ISnapshot newSnapshot             = new Snapshot(projectionId, version.ProjectionName, projectionState, snapshot.Revision + 1);
                    snapshotStore.Save(newSnapshot, version);
                    loadSnapshot = () => newSnapshot;

                    projectionCommits.Clear();

                    log.Debug(() => $"Snapshot created for projection `{version.ProjectionName}` with id={projectionId} where ({loadedCommits.Count}) were zipped. Snapshot: `{snapshot.GetType().Name}`");
                }

                if (loadedCommits.Count < snapshotStrategy.EventsInSnapshot)
                {
                    break;
                }

                if (loadedCommits.Count > snapshotStrategy.EventsInSnapshot * 1.5)
                {
                    log.Warn(() => $"Potential memory leak. The system will be down fairly soon. The projection `{version.ProjectionName}` with id={projectionId} loads a lot of projection commits ({loadedCommits.Count}) and snapshot `{snapshot.GetType().Name}` which puts a lot of CPU and RAM pressure. You can resolve this by configuring the snapshot settings`.");
                }
            }

            ProjectionStream stream = new ProjectionStream(projectionId, projectionCommits, loadSnapshot);

            return(stream);
        }
예제 #28
0
        public async IAsyncEnumerable <ProjectionCommit> EnumerateProjectionAsync(ProjectionVersion version, IBlobId projectionId)
        {
            if (projectionCommits.ContainsKey(version) == false)
            {
                yield break;
            }

            if (projectionCommits[version].ContainsKey(projectionId) == false)
            {
                yield break;
            }

            foreach (var commit in projectionCommits[version][projectionId])
            {
                yield return(commit);
            }
        }
예제 #29
0
        ProjectionStream LoadProjectionStream(Type projectionType, ProjectionVersion projectionVersion, IBlobId projectionId, ISnapshot snapshot)
        {
            ISnapshot currentSnapshot = snapshot;
            string    contractId      = projectionVersion.ProjectionContractId;

            List <ProjectionCommit> projectionCommits = new List <ProjectionCommit>();
            int snapshotMarker = snapshot.Revision;

            while (true)
            {
                snapshotMarker++;
                var loadedCommits = projectionStore.Load(projectionVersion, projectionId, snapshotMarker).ToList();
                if (loadedCommits.Count > 1000)
                {
                    log.Warn($"Potential memory leak. The system will be down fairly soon. The projection `{contractId}` for id={projectionId} loads a lot of projection commits ({loadedCommits.Count}) and snapshot `{snapshot.GetType().Name}` which puts a lot of CPU and RAM pressure. You can resolve this by enabling the Snapshots feature in the host which handles projection WRITES and READS using `.UseSnapshots(...)`.");
                }

                projectionCommits.AddRange(loadedCommits);
                bool isSnapshotable = typeof(IAmNotSnapshotable).IsAssignableFrom(projectionType) == false;

                if (isSnapshotable && snapshotStrategy.ShouldCreateSnapshot(projectionCommits, snapshot.Revision))
                {
                    ProjectionStream checkpointStream = new ProjectionStream(projectionId, projectionCommits, currentSnapshot);
                    var       projectionState         = checkpointStream.RestoreFromHistory(projectionType).Projection.State;
                    ISnapshot newSnapshot             = new Snapshot(projectionId, contractId, projectionState, snapshot.Revision + 1);
                    snapshotStore.Save(newSnapshot, projectionVersion);
                    currentSnapshot = newSnapshot;

                    projectionCommits.Clear();
                }
                else if (loadedCommits.Count() < snapshotStrategy.EventsInSnapshot)
                {
                    break;
                }
            }

            ProjectionStream stream = new ProjectionStream(projectionId, projectionCommits, currentSnapshot);

            return(stream);
        }
예제 #30
0
 public Task <bool> HasSnapshotMarkerAsync(ProjectionVersion version, IBlobId projectionId, int snapshotMarker)
 {
     return(Task.FromResult(false)); // We assume there are no snapshots in the InMemory implementation
 }