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 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))); } }
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()); }
private async Task <ProjectionStream> LoadProjectionStreamAsync(ProjectionVersion version, IBlobId projectionId, ISnapshot snapshot) { bool shouldLoadMore = true; Func <ISnapshot> loadSnapshot = () => snapshot; List <ProjectionCommit> projectionCommits = new List <ProjectionCommit>(); int snapshotMarker = snapshot.Revision; while (shouldLoadMore) { snapshotMarker++; var loadProjectionCommits = projectionStore.LoadAsync(version, projectionId, snapshotMarker).ConfigureAwait(false); bool checkNextSnapshotMarker = await projectionStore.HasSnapshotMarkerAsync(version, projectionId, snapshotMarker + 1).ConfigureAwait(false); shouldLoadMore = checkNextSnapshotMarker; await foreach (var commit in loadProjectionCommits) { projectionCommits.Add(commit); } } ProjectionStream stream = new ProjectionStream(projectionId, projectionCommits, loadSnapshot); return(stream); }
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 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)); }
IProjectionGetResult <PersistentProjectionVersionHandler> GetProjectionVersionsFromStore(string contractId) { var versionId = new ProjectionVersionManagerId(contractId); var persistentVersionType = typeof(PersistentProjectionVersionHandler); var persistentVersionContractId = persistentVersionType.GetContractId(); var persistentVersion = new ProjectionVersion(persistentVersionContractId, ProjectionStatus.Live, 1, persistentVersionType.GetProjectionHash()); ProjectionStream stream = LoadProjectionStream(persistentVersionType, persistentVersion, versionId, new NoSnapshot(versionId, contractId)); var queryResult = stream.RestoreFromHistory <PersistentProjectionVersionHandler>(); return(queryResult); }
ProjectionStream LoadProjectionStream(Type projectionType, ProjectionVersion projectionVersion, IBlobId projectionId, ISnapshot snapshot) { if (ReferenceEquals(null, projectionVersion)) { throw new ArgumentNullException(nameof(projectionVersion)); } if (ReferenceEquals(null, projectionId)) { throw new ArgumentNullException(nameof(projectionId)); } if (ReferenceEquals(null, snapshot)) { throw new ArgumentNullException(nameof(snapshot)); } ISnapshot currentSnapshot = snapshot; string contractId = projectionVersion.ProjectionName; List <ProjectionCommit> projectionCommits = new List <ProjectionCommit>(); int snapshotMarker = snapshot.Revision; while (true) { snapshotMarker++; var loadedCommits = projectionStore.Load(projectionVersion, projectionId, snapshotMarker).ToList(); 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(); log.Debug(() => $"Snapshot created for projection `{contractId}` with id={projectionId} where ({loadedCommits.Count}) were zipped. Snapshot: `{snapshot.GetType().Name}`"); } else if (loadedCommits.Count() < snapshotStrategy.EventsInSnapshot) { break; } else { log.Warn($"Potential memory leak. The system will be down fairly soon. The projection `{contractId}` 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, currentSnapshot); return(stream); }
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>()); }
ProjectionStream LoadProjectionStream(Type projectionType, ProjectionVersion version, IBlobId projectionId, SnapshotMeta snapshotMeta) { Func <ISnapshot> loadSnapshot = () => snapshotStore.Load(version.ProjectionName, projectionId, version); List <ProjectionCommit> projectionCommits = new List <ProjectionCommit>(); int snapshotMarker = snapshotMeta.Revision; while (true) { snapshotMarker++; var loadedCommits = projectionStore.Load(version, projectionId, snapshotMarker).ToList(); projectionCommits.AddRange(loadedCommits); if (projectionType.IsSnapshotable()) { if (snapshotStrategy.ShouldCreateSnapshot(projectionCommits, snapshotMeta.Revision)) { ProjectionStream checkpointStream = new ProjectionStream(projectionId, projectionCommits, loadSnapshot); var projectionState = checkpointStream.RestoreFromHistory(projectionType).State; ISnapshot newSnapshot = new Snapshot(projectionId, version.ProjectionName, projectionState, snapshotMeta.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: `{newSnapshot.GetType().Name}`"); } } else { loadSnapshot = () => new NoSnapshot(projectionId, version.ProjectionName); } 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}) 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 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)); } }
ReadResult <ProjectionVersionsHandler> GetProjectionVersionsFromStore(string projectionName) { try { var persistentVersionType = typeof(ProjectionVersionsHandler); var projectionVersions_ProjectionName = persistentVersionType.GetContractId(); var versionId = new ProjectionVersionManagerId(projectionName, context.Tenant); var persistentVersion = new ProjectionVersion(projectionVersions_ProjectionName, ProjectionStatus.Live, 1, projectionHasher.CalculateHash(persistentVersionType)); ProjectionStream stream = LoadProjectionStream(persistentVersionType, persistentVersion, versionId, new NoSnapshot(versionId, projectionVersions_ProjectionName).GetMeta()); var queryResult = stream.RestoreFromHistory <ProjectionVersionsHandler>(); return(new ReadResult <ProjectionVersionsHandler>(queryResult)); } catch (Exception ex) { return(ReadResult <ProjectionVersionsHandler> .WithNotFoundHint(ex.Message)); } }
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 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)); } }
private async Task <ReadResult <ProjectionVersionsHandler> > GetProjectionVersionsFromStoreAsync(string projectionName) { try { var persistentVersionType = typeof(ProjectionVersionsHandler); var projectionVersions_ProjectionName = persistentVersionType.GetContractId(); var versionId = new ProjectionVersionManagerId(projectionName, context.Tenant); var persistentVersion = new ProjectionVersion(projectionVersions_ProjectionName, ProjectionStatus.Live, 1, projectionHasher.CalculateHash(persistentVersionType)); ProjectionStream stream = await LoadProjectionStreamAsync(persistentVersionType, persistentVersion, versionId, new NoSnapshot(versionId, projectionVersions_ProjectionName).GetMeta()).ConfigureAwait(false); var queryResult = await stream.RestoreFromHistoryAsync <ProjectionVersionsHandler>().ConfigureAwait(false); return(new ReadResult <ProjectionVersionsHandler>(queryResult)); } catch (Exception ex) { log.WarnException(ex, () => $"Failed to load projection versions. ProjectionName: {projectionName}"); return(ReadResult <ProjectionVersionsHandler> .WithError(ex.Message)); } }
public void Save(Type projectionType, IEvent @event, EventOrigin eventOrigin) { if (ReferenceEquals(null, projectionType)) { throw new ArgumentNullException(nameof(projectionType)); } if (ReferenceEquals(null, @event)) { throw new ArgumentNullException(nameof(@event)); } if (ReferenceEquals(null, eventOrigin)) { throw new ArgumentNullException(nameof(eventOrigin)); } string contractId = projectionType.GetContractId(); var instance = FastActivator.CreateInstance(projectionType); var statefullProjection = instance as IProjectionDefinition; if (statefullProjection != null) { var projectionIds = statefullProjection.GetProjectionIds(@event); foreach (var version in GetProjectionVersions(contractId)) { foreach (var projectionId in projectionIds) { ISnapshot snapshot = snapshotStore.Load(contractId, projectionId, version); ProjectionStream projectionStream = LoadProjectionStream(projectionType, version, projectionId, snapshot); int snapshotMarker = snapshotStrategy.GetSnapshotMarker(projectionStream.Commits, snapshot.Revision); var commit = new ProjectionCommit(projectionId, version, @event, snapshotMarker, eventOrigin, DateTime.UtcNow); projectionStore.Save(commit); } } } }
private async Task <ProjectionStream> LoadProjectionStreamAsync(Type projectionType, IBlobId projectionId) { string projectionName = projectionType.GetContractId(); ReadResult <ProjectionVersions> result = await GetProjectionVersionsAsync(projectionName).ConfigureAwait(false); if (result.IsSuccess) { ProjectionVersion liveVersion = result.Data.GetLive(); if (liveVersion is null) { log.Warn(() => $"Unable to find projection `live` version. {Environment.NewLine}AvailableVersions:{Environment.NewLine}{result.Data.ToString()}"); return(ProjectionStream.Empty()); } ISnapshot snapshot = projectionType.IsSnapshotable() ? await snapshotStore.LoadAsync(projectionName, projectionId, liveVersion).ConfigureAwait(false) : new NoSnapshot(projectionId, projectionName); return(await LoadProjectionStreamAsync(liveVersion, projectionId, snapshot)); } return(ProjectionStream.Empty()); }
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 void Save(Type projectionType, CronusMessage cronusMessage) { if (ReferenceEquals(null, projectionType)) { throw new ArgumentNullException(nameof(projectionType)); } if (ReferenceEquals(null, cronusMessage)) { throw new ArgumentNullException(nameof(cronusMessage)); } var projection = FastActivator.CreateInstance(projectionType) as IProjectionDefinition; if (projection != null) { var projectionIds = projection.GetProjectionIds(cronusMessage.Payload as IEvent); string contractId = projectionType.GetContractId(); foreach (var projectionId in projectionIds) { foreach (var version in GetProjectionVersions(contractId)) { ISnapshot snapshot = snapshotStore.Load(contractId, projectionId, version); ProjectionStream projectionStream = LoadProjectionStream(projectionType, version, projectionId, snapshot); int snapshotMarker = snapshotStrategy.GetSnapshotMarker(projectionStream.Commits, snapshot.Revision); EventOrigin eventOrigin = cronusMessage.GetEventOrigin(); DateTime timestamp = DateTime.UtcNow; IEvent @event = cronusMessage.Payload as IEvent; var commit = new ProjectionCommit(projectionId, version, @event, snapshotMarker, eventOrigin, timestamp); projectionStore.Save(commit); } } } }
public void Save(Type projectionType, IEvent @event, EventOrigin eventOrigin) { if (ReferenceEquals(null, projectionType)) { throw new ArgumentNullException(nameof(projectionType)); } if (ReferenceEquals(null, @event)) { throw new ArgumentNullException(nameof(@event)); } if (ReferenceEquals(null, eventOrigin)) { throw new ArgumentNullException(nameof(eventOrigin)); } string projectionName = projectionType.GetContractId(); var handlerInstance = handlerFactory.Create(projectionType); var projection = handlerInstance.Current as IProjectionDefinition; if (projection != null) { var projectionIds = projection.GetProjectionIds(@event); foreach (var projectionId in projectionIds) { ReadResult <ProjectionVersions> result = GetProjectionVersions(projectionName); if (result.IsSuccess) { foreach (ProjectionVersion version in result.Data) { if (version.Status == ProjectionStatus.Building || version.Status == ProjectionStatus.Live) { try { SnapshotMeta snapshotMeta = null; if (projectionType.IsSnapshotable()) { snapshotMeta = snapshotStore.LoadMeta(projectionName, projectionId, version); } else { snapshotMeta = new NoSnapshot(projectionId, projectionName).GetMeta(); } ProjectionStream projectionStream = LoadProjectionStream(projectionType, version, projectionId, snapshotMeta); int snapshotMarker = snapshotStrategy.GetSnapshotMarker(projectionStream.Commits, snapshotMeta.Revision); var commit = new ProjectionCommit(projectionId, version, @event, snapshotMarker, eventOrigin, DateTime.UtcNow); projectionStore.Save(commit); } catch (Exception ex) { log.ErrorException("Failed to persist event." + Environment.NewLine + $"\tProjectionVersion:{version}" + Environment.NewLine + $"\tEvent:{@event}", ex); } } else if (version.Status == ProjectionStatus.NotPresent) { var commit = new ProjectionCommit(projectionId, version, @event, 1, eventOrigin, DateTime.UtcNow); projectionStore.Save(commit); } } } } } }
public void Save(Type projectionType, IEvent @event, EventOrigin eventOrigin, ProjectionVersion version) { if (ReferenceEquals(null, projectionType)) { throw new ArgumentNullException(nameof(projectionType)); } if (ReferenceEquals(null, @event)) { throw new ArgumentNullException(nameof(@event)); } if (ReferenceEquals(null, eventOrigin)) { throw new ArgumentNullException(nameof(eventOrigin)); } if (ReferenceEquals(null, version)) { throw new ArgumentNullException(nameof(version)); } if ((version.Status == ProjectionStatus.Building || version.Status == ProjectionStatus.Live) == false) { throw new ArgumentException("Invalid version. Only versions in `Building` and `Live` status are eligable for persistence.", nameof(version)); } string projectionName = projectionType.GetContractId(); if (projectionName.Equals(version.ProjectionName, StringComparison.OrdinalIgnoreCase) == false) { throw new ArgumentException($"Invalid version. The version `{version}` does not match projection `{projectionName}`", nameof(version)); } var handlerInstance = handlerFactory.Create(projectionType); var projection = handlerInstance.Current as IProjectionDefinition; if (projection != null) { var projectionIds = projection.GetProjectionIds(@event); foreach (var projectionId in projectionIds) { try { SnapshotMeta snapshotMeta = null; if (projectionType.IsSnapshotable()) { snapshotMeta = snapshotStore.LoadMeta(projectionName, projectionId, version); } else { snapshotMeta = new NoSnapshot(projectionId, projectionName).GetMeta(); } ProjectionStream projectionStream = LoadProjectionStream(projectionType, version, projectionId, snapshotMeta); int snapshotMarker = snapshotStrategy.GetSnapshotMarker(projectionStream.Commits, snapshotMeta.Revision); var commit = new ProjectionCommit(projectionId, version, @event, snapshotMarker, eventOrigin, DateTime.UtcNow); projectionStore.Save(commit); } catch (Exception ex) { log.ErrorException("Failed to persist event." + Environment.NewLine + $"\tProjectionVersion:{version}" + Environment.NewLine + $"\tEvent:{@event}", ex); } } } }