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;
            }
        }
Exemplo n.º 2
0
        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));
        }
Exemplo n.º 3
0
        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);
        }
Exemplo n.º 4
0
        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);
                        }
                    }
                }
            }
        }
Exemplo n.º 5
0
        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;
            }
        }
Exemplo n.º 7
0
 public void Subscribe(IStreamStore streamStore, StreamId streamId)
 {
     StreamSubscription = streamStore.SubscribeToStream(streamId, null, StreamMessageReceived);
 }
Exemplo n.º 8
0
 public BalanceProjection(IStreamStore streamStore, StreamId streamId)
 {
     streamStore.SubscribeToStream(streamId, null, StreamMessageReceived);
 }
Exemplo n.º 9
0
 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));
 }
Exemplo n.º 10
0
        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);
        }