public async Task <RoadNetworkChangesArchive> Get(ArchiveId id, CancellationToken ct = default) { var stream = new StreamName(id); if (_map.TryGet(stream, out var entry)) { return((RoadNetworkChangesArchive)entry.Entity); } var page = await _store.ReadStreamForwards(stream, StreamVersion.Start, 1024, ct); if (page.Status == PageReadStatus.StreamNotFound) { var network = RoadNetworkChangesArchive.Factory(); _map.Attach(new EventSourcedEntityMapEntry(network, stream, ExpectedVersion.NoStream)); return(network); } IEventSourcedEntity entity = RoadNetworkChangesArchive.Factory(); var messages = new List <object>(page.Messages.Length); foreach (var message in page.Messages) { messages.Add( JsonConvert.DeserializeObject( await message.GetJsonData(ct), _mapping.GetEventType(message.Type), _settings)); } entity.RestoreFromEvents(messages.ToArray()); while (!page.IsEnd) { messages.Clear(); page = await page.ReadNext(ct); if (page.Status == PageReadStatus.StreamNotFound) { var network = RoadNetworkChangesArchive.Factory(); _map.Attach(new EventSourcedEntityMapEntry(network, stream, ExpectedVersion.NoStream)); return(network); } foreach (var message in page.Messages) { messages.Add( JsonConvert.DeserializeObject( await message.GetJsonData(ct), _mapping.GetEventType(message.Type), _settings)); } entity.RestoreFromEvents(messages.ToArray()); } _map.Attach(new EventSourcedEntityMapEntry(entity, stream, page.LastStreamVersion)); return((RoadNetworkChangesArchive)entity); }
public async Task <Organization> TryGet(OrganizationId id, CancellationToken ct = default) { var stream = StreamNameFactory(id); if (_map.TryGet(stream, out var entry)) { return((Organization)entry.Entity); } var organization = Organization.Factory(); var page = await _store.ReadStreamForwards(stream, StreamVersion.Start, 100, ct); if (page.Status == PageReadStatus.StreamNotFound) { return(null); } IEventSourcedEntity entity = organization; var messages = new List <object>(page.Messages.Length); foreach (var message in page.Messages) { messages.Add( JsonConvert.DeserializeObject( await message.GetJsonData(ct), _mapping.GetEventType(message.Type), _settings)); } entity.RestoreFromEvents(messages.ToArray()); while (!page.IsEnd) { messages.Clear(); page = await page.ReadNext(ct); if (page.Status == PageReadStatus.StreamNotFound) { return(null); } foreach (var message in page.Messages) { messages.Add( JsonConvert.DeserializeObject( await message.GetJsonData(ct), _mapping.GetEventType(message.Type), _settings)); } entity.RestoreFromEvents(messages.ToArray()); } _map.Attach(new EventSourcedEntityMapEntry(entity, stream, page.LastStreamVersion)); return(organization); }
private object Deserialize(StreamMessage message) { var eventData = message.GetJsonData().GetAwaiter().GetResult(); var eventType = _eventMapping.GetEventType(message.Type); return(_eventDeserializer.DeserializeObject(eventData, eventType)); }
private Fact MapToFact(StreamMessage streamMessage) { var eventType = _eventMapping.GetEventType(streamMessage.Type); var eventData = streamMessage.GetJsonData().GetAwaiter().GetResult(); var @event = _eventDeserializer.DeserializeObject(eventData, eventType); return(new Fact(streamMessage.StreamId, @event)); }
private async Task <RecordedEvent[]> ReadThens(long position) { var recorded = new List <RecordedEvent>(); var page = await _store.ReadAllForwards(position, 1024); foreach (var then in page.Messages) { recorded.Add( new RecordedEvent( new StreamName(then.StreamId), JsonConvert.DeserializeObject( await then.GetJsonData(), _mapping.GetEventType(then.Type), _settings ) ) ); } while (!page.IsEnd) { page = await page.ReadNext(); foreach (var then in page.Messages) { recorded.Add( new RecordedEvent( new StreamName(then.StreamId), JsonConvert.DeserializeObject( await then.GetJsonData(), _mapping.GetEventType(then.Type), _settings ) ) ); } } return(recorded.ToArray()); }
public EventProcessor( IStreamStore streamStore, IEventProcessorPositionStore positionStore, AcceptStreamMessageFilter filter, EventHandlerDispatcher dispatcher, Scheduler scheduler, ILogger <EventProcessor> logger) { if (streamStore == null) { throw new ArgumentNullException(nameof(streamStore)); } if (positionStore == null) { throw new ArgumentNullException(nameof(positionStore)); } if (filter == null) { throw new ArgumentNullException(nameof(filter)); } if (dispatcher == null) { throw new ArgumentNullException(nameof(dispatcher)); } _scheduler = scheduler ?? throw new ArgumentNullException(nameof(scheduler)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _messagePumpCancellation = new CancellationTokenSource(); _messageChannel = Channel.CreateUnbounded <object>(new UnboundedChannelOptions { SingleReader = true, SingleWriter = false, AllowSynchronousContinuations = false }); _messagePump = Task.Factory.StartNew(async() => { IAllStreamSubscription subscription = null; try { logger.LogInformation("EventProcessor message pump entered ..."); while (await _messageChannel.Reader.WaitToReadAsync(_messagePumpCancellation.Token).ConfigureAwait(false)) { while (_messageChannel.Reader.TryRead(out var message)) { switch (message) { case Subscribe _: logger.LogInformation("Subscribing ..."); subscription?.Dispose(); var position = await positionStore .ReadPosition(RoadNetworkArchiveEventQueue, _messagePumpCancellation.Token) .ConfigureAwait(false); logger.LogInformation("Subscribing as of {0}", position ?? -1L); subscription = streamStore.SubscribeToAll( position, async(_, streamMessage, token) => { if (filter(streamMessage)) { var command = new ProcessStreamMessage(streamMessage); await _messageChannel.Writer.WriteAsync(command, token).ConfigureAwait(false); await command.Completion.ConfigureAwait(false); } else if (streamMessage.Position % RecordPositionThreshold == 0 && !_messagePumpCancellation.IsCancellationRequested) { await _messageChannel.Writer .WriteAsync(new RecordPosition(streamMessage), token) .ConfigureAwait(false); } else { logger.LogInformation("Skipping {MessageType} at {Position}", streamMessage.Type, streamMessage.Position); } }, async(_, reason, exception) => { if (!_messagePumpCancellation.IsCancellationRequested) { await _messageChannel.Writer .WriteAsync(new SubscriptionDropped(reason, exception), _messagePumpCancellation.Token) .ConfigureAwait(false); } }, prefetchJsonData: false, name: "RoadRegistry.BackOffice.EventHost.EventProcessor"); break; case RecordPosition record: try { logger.LogInformation("Recording position of {MessageType} at {Position}.", record.Message.Type, record.Message.Position); await positionStore .WritePosition( RoadNetworkArchiveEventQueue, record.Message.Position, _messagePumpCancellation.Token) .ConfigureAwait(false); } catch (Exception exception) { logger.LogError(exception, exception.Message); } break; case ProcessStreamMessage process: try { logger.LogInformation("Processing {MessageType} at {Position}", process.Message.Type, process.Message.Position); var body = JsonConvert.DeserializeObject( await process.Message.GetJsonData(_messagePumpCancellation.Token).ConfigureAwait(false), EventMapping.GetEventType(process.Message.Type), SerializerSettings); var @event = new Event(body).WithMessageId(process.Message.MessageId); await dispatcher(@event, _messagePumpCancellation.Token).ConfigureAwait(false); await positionStore .WritePosition( RoadNetworkArchiveEventQueue, process.Message.Position, _messagePumpCancellation.Token) .ConfigureAwait(false); process.Complete(); } catch (Exception exception) { logger.LogError(exception, exception.Message); // how are we going to recover from this? do we even need to recover from this? // prediction: it's going to be a serialization error, a data quality error, or a bug process.Fault(exception); } break; case SubscriptionDropped dropped: if (dropped.Reason == SubscriptionDroppedReason.StreamStoreError) { logger.LogError(dropped.Exception, "Subscription was dropped because of a stream store error"); await scheduler.Schedule(async token => { if (!_messagePumpCancellation.IsCancellationRequested) { await _messageChannel.Writer.WriteAsync(new Subscribe(), token).ConfigureAwait(false); } }, ResubscribeAfter).ConfigureAwait(false); } else if (dropped.Reason == SubscriptionDroppedReason.SubscriberError) { logger.LogError(dropped.Exception, "Subscription was dropped because of a subscriber error"); if (dropped.Exception != null && dropped.Exception is SqlException sqlException && sqlException.Number == -2 /* timeout */) { await scheduler.Schedule(async token => { if (!_messagePumpCancellation.IsCancellationRequested) { await _messageChannel.Writer.WriteAsync(new Subscribe(), token).ConfigureAwait(false); } }, ResubscribeAfter).ConfigureAwait(false); } } break; } } } } catch (TaskCanceledException) { if (logger.IsEnabled(LogLevel.Information)) { logger.Log(LogLevel.Information, "EventProcessor message pump is exiting due to cancellation."); } } catch (OperationCanceledException) { if (logger.IsEnabled(LogLevel.Information)) { logger.Log(LogLevel.Information, "EventProcessor message pump is exiting due to cancellation."); } } catch (Exception exception) { logger.LogError(exception, "EventProcessor message pump is exiting due to a bug."); } finally { subscription?.Dispose(); } }, _messagePumpCancellation.Token, TaskCreationOptions.LongRunning | TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); }
public async Task <RoadNetwork> Get(CancellationToken ct = default) { if (_map.TryGet(Stream, out var entry)) { return((RoadNetwork)entry.Entity); } var roadNetwork = RoadNetwork.Factory(); var(snapshot, version) = await _snapshotReader.ReadSnapshot(ct); if (version != ExpectedVersion.NoStream) { roadNetwork.RestoreFromSnapshot(snapshot); version += 1; } else { version = StreamVersion.Start; } var page = await _store.ReadStreamForwards(Stream, version, StreamPageSize, ct); if (page.Status == PageReadStatus.StreamNotFound) { var initial = RoadNetwork.Factory(); _map.Attach(new EventSourcedEntityMapEntry(initial, Stream, ExpectedVersion.NoStream)); return(initial); } IEventSourcedEntity entity = roadNetwork; var messages = new List <object>(page.Messages.Length); foreach (var message in page.Messages) { messages.Add( JsonConvert.DeserializeObject( await message.GetJsonData(ct), _mapping.GetEventType(message.Type), _settings)); } entity.RestoreFromEvents(messages.ToArray()); while (!page.IsEnd) { messages.Clear(); page = await page.ReadNext(ct); if (page.Status == PageReadStatus.StreamNotFound) { var initial = RoadNetwork.Factory(); _map.Attach(new EventSourcedEntityMapEntry(initial, Stream, ExpectedVersion.NoStream)); return(initial); } foreach (var message in page.Messages) { messages.Add( JsonConvert.DeserializeObject( await message.GetJsonData(ct), _mapping.GetEventType(message.Type), _settings)); } entity.RestoreFromEvents(messages.ToArray()); } _map.Attach(new EventSourcedEntityMapEntry(entity, Stream, page.LastStreamVersion)); return(roadNetwork); }