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()); }
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()); }
public Snapshot(IBlobId id, string projectionContractId, object state, int revision) { Id = id; ProjectionContractId = projectionContractId; State = state; Revision = revision; }
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))); } }
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)); } } }
public Snapshot(IBlobId id, string projectionName, object state, int revision) { Id = id; ProjectionName = projectionName; State = state; Revision = revision; }
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; }
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; }
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))); }
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)); }
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>()); }
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); } }
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}"); }
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)); } }
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; }
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}"); }
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; }
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)); } }
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)); } }
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()); } }
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); }
public NoSnapshot(IBlobId id, string projectionName) { Id = id; ProjectionName = projectionName; }
public AggregateCommit(IBlobId aggregateId, int revision, List <IEvent> events) : this(aggregateId.RawId, revision, events) { }
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); }
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); } }
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); }
public Task <bool> HasSnapshotMarkerAsync(ProjectionVersion version, IBlobId projectionId, int snapshotMarker) { return(Task.FromResult(false)); // We assume there are no snapshots in the InMemory implementation }