public void Save(Type projectionType, CronusMessage 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) { 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); } } } }
public void Throws_on_read_timeout() { bool checkpointRead = false; var reader = Sys.ActorOf(conf => { conf.Receive <ReadProjectionCheckpointRequest>((r, ctx) => { ctx.Sender.Tell(new ReadProjectionCheckpointResponse(r.RequestID, 0)); checkpointRead = true; }); }); var options = new GlobalOptions { ReadRequestTimeout = TimeSpan.FromMilliseconds(300) }; var props = ProjectionStream.CreateProps(new ProjectionStreamQuery(), reader, ActorRefs.Nobody, options); Sys.ActorOf(c => { c.OnPreStart = ctx => ctx.ActorOf(props); c.Strategy = new OneForOneStrategy(ex => { TestActor.Tell(ex); return(Directive.Stop); }); }); ExpectMsg <Exception>(); Assert.True(checkpointRead); }
public void Requests_checkpoint_on_start() { var reader = CreateTestProbe(); var props = ProjectionStream.CreateProps(new ProjectionStreamQuery(), reader, ActorRefs.Nobody, new GlobalOptions()); Sys.ActorOf(props); reader.ExpectMsg <ReadProjectionCheckpointRequest>(); }
public void Sends_ProjectionReplayFinished_to_uptodate_subscriber() { var reader = CreateWorkingReader(); var query = new ProjectionStreamQuery(); var props = ProjectionStream.CreateProps(query, reader, ActorRefs.Nobody, new GlobalOptions()); var ps = Sys.ActorOf(props); var subscriber = CreateTestProbe(); ps.Tell(new ProjectionSubscriptionRequest(query, 0), subscriber); subscriber.ExpectMsg <ProjectionReplayFinished>(); }
public void Sends_RebuildProjection_to_subscriber_with_unknown_sequence() { var reader = CreateWorkingReader(0); var query = new ProjectionStreamQuery(); var props = ProjectionStream.CreateProps(query, reader, ActorRefs.Nobody, new GlobalOptions()); var ps = Sys.ActorOf(props); var subscriber = CreateTestProbe(); // projection stream only knows event 0, projection says it knows 99 ps.Tell(new ProjectionSubscriptionRequest(query, 99), subscriber); subscriber.ExpectMsg <RebuildProjection>(); }
public void Requests_events_after_checkpoint() { var reader = Sys.ActorOf(conf => { conf.Receive <ReadProjectionCheckpointRequest>((r, ctx) => ctx.Sender.Tell(new ReadProjectionCheckpointResponse(r.RequestID, 0))); conf.Receive <ReadRequest>((r, ctx) => TestActor.Forward(r)); }); var props = ProjectionStream.CreateProps(new ProjectionStreamQuery(), reader, ActorRefs.Nobody, new GlobalOptions()); Sys.ActorOf(props); ExpectMsg <ReadRequest>(); }
public void SubscriptionRequest_with_past_sequence_starts_projection_replay_worker() { var workerProps = Props.Create <ProbeRelay>(TestActor); var reader = CreateWorkingReader(1); var query = new ProjectionStreamQuery(new DomainEventPredicate(typeof(TestEvent))); var props = ProjectionStream.CreateProps(query, reader, ActorRefs.Nobody, new GlobalOptions(), workerProps); var ps = Sys.ActorOf(props); var subscriber = CreateTestProbe(); ps.Tell(new ProjectionSubscriptionRequest(query, 0), subscriber); ExpectMsg <InitializeProjectionReplayWorker>(); }
public void Requests_matched_events_be_written_to_index() { var query = new ProjectionStreamQuery(new DomainEventPredicate(typeof(TestEvent))); var writer = CreateTestProbe(); var props = ProjectionStream.CreateProps(query, CreateWorkingReader(), writer, new GlobalOptions()); var ps = Sys.ActorOf(props); ps.Tell(MockPersistedEvent.Create(new object(), 1)); ps.Tell(MockPersistedEvent.Create(new TestEvent(), 2)); ps.Tell(MockPersistedEvent.Create(new object(), 3)); ps.Tell(MockPersistedEvent.Create(new TestEvent(), 4)); ps.Tell(MockPersistedEvent.Create(new object(), 5)); writer.ExpectMsg <ProjectionIndexPersistenceRequest>(m => m.ProjectionStream.Equals(query.ProjectionStream) && m.ProjectionStreamSequence == 1 && m.GlobalSequence == 2); writer.ExpectMsg <ProjectionIndexPersistenceRequest>(m => m.ProjectionStream.Equals(query.ProjectionStream) && m.ProjectionStreamSequence == 2 && m.GlobalSequence == 4); writer.ExpectNoMsg(TimeSpan.FromMilliseconds(500)); }
ProjectionVersions GetProjectionVersions(string contractId) { ProjectionVersions versions = inMemoryVersionStore.Get(contractId); if (versions == null || versions.Count == 0) { 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(typeof(PersistentProjectionVersionHandler), persistentVersion, versionId, new NoSnapshot(versionId, contractId)); var queryResult = stream.RestoreFromHistory <PersistentProjectionVersionHandler>(); if (queryResult.Success) { if (queryResult.Projection.State.Live != null) { inMemoryVersionStore.Cache(queryResult.Projection.State.Live); } if (queryResult.Projection.State.Building != null) { inMemoryVersionStore.Cache(queryResult.Projection.State.Building); } versions = inMemoryVersionStore.Get(contractId); } // inception if (versions == null || versions.Count == 0) { if (string.Equals(persistentVersionContractId, contractId, StringComparison.OrdinalIgnoreCase)) { inMemoryVersionStore.Cache(persistentVersion); versions = inMemoryVersionStore.Get(contractId); } else { var initialVersion = new ProjectionVersion(contractId, ProjectionStatus.Building, 1, contractId.GetTypeByContract().GetProjectionHash()); inMemoryVersionStore.Cache(initialVersion); versions = inMemoryVersionStore.Get(contractId); } } } return(versions ?? new ProjectionVersions()); }
public async Task Sends_ProjectionUnsubscribed_to_subscribers_on_restart() { var query = new ProjectionStreamQuery(); var reader = CreateWorkingReader(); var props = ProjectionStream.CreateProps(query, reader, ActorRefs.Nobody, new GlobalOptions()); var ps = Sys.ActorOf(props); var subscriber = Sys.ActorOf(conf => { conf.Receive <ProjectionReplayFinished>((m, ctx) => { }); conf.ReceiveAny((o, ctx) => TestActor.Forward(o)); }); ps.Tell(new ProjectionSubscriptionRequest(query, 0), subscriber); await Task.Delay(100); ps.Tell(Kill.Instance); ExpectMsg <ProjectionUnsubscribed>(); }
public void Throws_on_checkpoint_abort() { var reader = Sys.ActorOf(conf => { conf.Receive <ReadProjectionCheckpointRequest>((r, ctx) => ctx.Sender.Tell(new Aborted(r.RequestID, new Exception()))); }); var props = ProjectionStream.CreateProps(new ProjectionStreamQuery(), reader, ActorRefs.Nobody, new GlobalOptions()); Sys.ActorOf(c => { c.OnPreStart = ctx => ctx.ActorOf(props); c.Strategy = new OneForOneStrategy(ex => { TestActor.Tell(ex); return(Directive.Stop); }); }); ExpectMsg <Exception>(); }
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 void Throws_on_checkpoint_timeout() { var options = new GlobalOptions { ReadRequestTimeout = TimeSpan.FromMilliseconds(300) }; var props = ProjectionStream.CreateProps(new ProjectionStreamQuery(), ActorRefs.Nobody, ActorRefs.Nobody, options); Sys.ActorOf(c => { c.OnPreStart = ctx => ctx.ActorOf(props); c.Strategy = new OneForOneStrategy(ex => { TestActor.Tell(ex); return(Directive.Stop); }); }); ExpectMsg <Exception>(); }
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 void Subscribers_that_received_RebuildProjection_need_to_resubscribe_to_receive_messages() { var reader = CreateWorkingReader(); var query = new ProjectionStreamQuery(new DomainEventPredicate(typeof(TestEvent))); var props = ProjectionStream.CreateProps(query, reader, ActorRefs.Nobody, new GlobalOptions()); var ps = Sys.ActorOf(props); var subscriber = Sys.ActorOf(conf => { conf.Receive <RebuildProjection>((r, ctx) => { }); conf.ReceiveAny((o, ctx) => TestActor.Forward(o)); }); // subscribe with invalid sequence ps.Tell(new ProjectionSubscriptionRequest(query, 10), subscriber); //publish to event stream var e = MockPersistedEvent.Create(new TestEvent()); Sys.EventStream.Publish(e); // expects the domain event to be the same ExpectNoMsg(TimeSpan.FromSeconds(1)); }
public void Publishes_events_from_eventstream_to_subscribers() { var reader = CreateWorkingReader(); var query = new ProjectionStreamQuery(new DomainEventPredicate(typeof(TestEvent))); var props = ProjectionStream.CreateProps(query, reader, ActorRefs.Nobody, new GlobalOptions()); var ps = Sys.ActorOf(props); var subscriber = Sys.ActorOf(conf => { conf.Receive <ProjectionReplayFinished>((r, ctx) => { }); conf.ReceiveAny((o, ctx) => TestActor.Forward(o)); }); // subscribe ps.Tell(new ProjectionSubscriptionRequest(query, 0), subscriber); //publish to event stream var e = MockPersistedEvent.Create(new TestEvent()); Sys.EventStream.Publish(e); // expects the domain event to be the same ExpectMsg <IPersistedStreamEvent>(m => m.DomainEvent == e.DomainEvent, TimeSpan.FromSeconds(15)); }