protected override async Task ConnectAsync() { //Get subscription position _position = await _subscriptionManager.GetSubscriptionPosition(_subscriptionId, true); _store = await _storeProvider.GetStreamStore(); if (_streamId == null) { _allSubscription = _store.SubscribeToAll(_position, HandleSubscriptionEvent, HandleSubscriptionDropped); _status = SubscriptionConnectionStatus.Connected; _startDate = DateTime.UtcNow; } else { int?intPos = (_position != null) ? Convert.ToInt32(_position) : default(int?); _subscription = _store.SubscribeToStream(_streamId.Id, intPos, HandleSubscriptionEvent, HandleSubscriptionDropped); _status = SubscriptionConnectionStatus.Connected; _startDate = DateTime.UtcNow; } }
public IJournalSubscription Subscribe(long @from, Action <JournalRecord> handler) { async Task MessageReceived(IStreamSubscription subscription, StreamMessage message, CancellationToken cancellationToken) { var command = (Command)_serializer.FromString(await message.GetJsonData()); var journalRecord = new JournalRecord(message.StreamVersion, message.CreatedUtc, command); handler.Invoke(journalRecord); } // pass null to subscribe from the beginning //or the version of the previous record int?version = null; if (from > 0) { version = (int)from - 1; } bool caughtUp = false; var sub = _streamStore.SubscribeToStream( _streamId, version, MessageReceived, SubscriptionDropped, hasCaughtUp => caughtUp = hasCaughtUp); sub.MaxCountPerRead = 100; return(new SqlStreamStoreSubscription(sub, () => caughtUp)); }
public IDisposable WatchForChanges(int version, OnSettingsChanged onSettingsChanged, CancellationToken ct) { IStreamSubscription subscription = null; async Task StreamMessageReceived(IStreamSubscription _, StreamMessage streamMessage, CancellationToken cancellationToken) { var settings = await StreamStoreConfigRepository.BuildConfigurationSettingsFromMessage(streamMessage, _messageHooks, ct); await onSettingsChanged(settings, ct); }; void SubscriptionDropped(IStreamSubscription _, SubscriptionDroppedReason reason, Exception exception = null) { if (reason != SubscriptionDroppedReason.Disposed) { SetupSubscription(); } }; void SetupSubscription() { subscription = _streamStore.SubscribeToStream( streamId: _streamId, continueAfterVersion: version, streamMessageReceived: StreamMessageReceived, subscriptionDropped: SubscriptionDropped); } SetupSubscription(); return(subscription); }
public IEnumerable <JournalRecord> GetRecords(long fromRecord = 0) { using (var queue = new BlockingCollection <JournalRecord>()) { async Task MessageReceived(IStreamSubscription subscription, StreamMessage message, CancellationToken cancellationToken) { var json = await message.GetJsonData(cancellationToken); var command = (Command)_serializer.FromString(json); var journalRecord = new JournalRecord(message.StreamVersion, message.CreatedUtc, command); queue.Add(journalRecord); } // pass null to subscribe from the beginning //or the version of the previous record int?version = null; if (fromRecord > 0) { version = (int)fromRecord - 1; } var caughtUp = false; using ( var sub = _streamStore.SubscribeToStream( _streamId, version, MessageReceived, SubscriptionDropped, hasCaughtUp => caughtUp = hasCaughtUp)) { sub.MaxCountPerRead = 100; while (!caughtUp || queue.Any()) { if (queue.TryTake(out var journalRecord)) { yield return(journalRecord); } else if (!caughtUp) { Thread.Sleep(100); } } } } }
public BalanceProjection(IStreamStore streamStore, StreamId streamId) { var mapBuilder = new EventMapBuilder <Balance>(); mapBuilder.Map <Deposited>().As((deposited, balance) => { balance.Add(deposited.Amount); }); mapBuilder.Map <Withdrawn>().As((withdrawn, balance) => { balance.Subtract(withdrawn.Amount); }); _map = mapBuilder.Build(new ProjectorMap <Balance>() { Custom = (context, projector) => projector() }); streamStore.SubscribeToStream(streamId, null, StreamMessageReceived); }
protected override async Task ConnectAsync() { _store = await _storeProvider.GetStreamStore(); if (_streamId == null) { _allSubscription = _store.SubscribeToAll( _startPosition == StreamPosition.End ? -1 : 0, (_, message, cancellationToken) => { return(HandleEvent(message, cancellationToken)); }, (sub, reason, ex) => { HandleSubscriptionDropped(sub, reason, ex); }); _status = SubscriptionConnectionStatus.Connected; _startDate = DateTime.UtcNow; } else { _streamSubscription = _store.SubscribeToStream( _streamId.Id, _startPosition == StreamPosition.End ? -1 : 0, (_, message, cancellationToken) => { return(HandleEvent(message, cancellationToken)); }, (sub, reason, ex) => { HandleSubscriptionDropped(sub, reason, ex); }); _status = SubscriptionConnectionStatus.Connected; _startDate = DateTime.UtcNow; } }
public void Subscribe(IStreamStore streamStore, StreamId streamId) { StreamSubscription = streamStore.SubscribeToStream(streamId, null, StreamMessageReceived); }
public BalanceProjection(IStreamStore streamStore, StreamId streamId) { streamStore.SubscribeToStream(streamId, null, StreamMessageReceived); }
public IStreamSubscription SubscribeToStream(StreamId streamId, int?continueAfterVersion, StreamMessageReceived streamMessageReceived, SubscriptionDropped subscriptionDropped = null, HasCaughtUp hasCaughtUp = null, bool prefetchJsonData = true, string name = null) { return(_store.SubscribeToStream(streamId, continueAfterVersion, streamMessageReceived, subscriptionDropped, hasCaughtUp, prefetchJsonData, name)); }
public CommandProcessor( IStreamStore streamStore, ICommandProcessorPositionStore positionStore, CommandHandlerDispatcher dispatcher, Scheduler scheduler, ILogger <CommandProcessor> logger) { if (streamStore == null) { throw new ArgumentNullException(nameof(streamStore)); } if (positionStore == null) { throw new ArgumentNullException(nameof(positionStore)); } 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 = true }); _messagePump = Task.Factory.StartNew(async() => { IStreamSubscription subscription = null; try { 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 version = await positionStore .ReadVersion(RoadNetworkCommandQueue, _messagePumpCancellation.Token) .ConfigureAwait(false); logger.LogInformation("Subscribing as of {0}", version ?? -1); subscription = streamStore.SubscribeToStream( RoadNetworkCommandQueue, version, async(_, streamMessage, token) => { var command = new ProcessStreamMessage(streamMessage); await _messageChannel.Writer .WriteAsync(command, token) .ConfigureAwait(false); await command .Completion .ConfigureAwait(false); }, async(_, reason, exception) => { if (!_messagePumpCancellation.IsCancellationRequested) { await _messageChannel.Writer .WriteAsync( new SubscriptionDropped(reason, exception), _messagePumpCancellation.Token) .ConfigureAwait(false); } }, name: "RoadRegistry.BackOffice.CommandHost.CommandProcessor"); break; case ProcessStreamMessage process: try { logger.LogDebug( "Processing {MessageType} at {Position}", process.Message.Type, process.Message.Position); var body = JsonConvert.DeserializeObject( await process.Message .GetJsonData(_messagePumpCancellation.Token) .ConfigureAwait(false), CommandMapping.GetEventType(process.Message.Type), SerializerSettings); var command = new Command(body).WithMessageId(process.Message.MessageId); await dispatcher(command, _messagePumpCancellation.Token).ConfigureAwait(false); await positionStore .WriteVersion(RoadNetworkCommandQueue, process.Message.StreamVersion, _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 // if (process.Message.StreamVersion == 0) // { // await positionStore.WriteVersion(RoadNetworkCommandQueue, // process.Message.StreamVersion, // _messagePumpCancellation.Token); // } 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); } 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); } } break; } } } } catch (TaskCanceledException) { if (logger.IsEnabled(LogLevel.Information)) { logger.Log(LogLevel.Information, "CommandProcessor message pump is exiting due to cancellation."); } } catch (OperationCanceledException) { if (logger.IsEnabled(LogLevel.Information)) { logger.Log(LogLevel.Information, "CommandProcessor message pump is exiting due to cancellation."); } } catch (Exception exception) { logger.LogError(exception, "CommandProcessor message pump is exiting due to a bug."); } finally { subscription?.Dispose(); } }, _messagePumpCancellation.Token, TaskCreationOptions.LongRunning | TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); }