Exemplo n.º 1
0
            public override void PreStart()
            {
                _callback = GetAsyncCallback <IReadOnlyList <IPersistentRepresentation> >(events =>
                {
                    if (events.Count == 0)
                    {
                        if (_currentSequenceNr > _toSequenceNr)
                        {
                            // end has been reached
                            CompleteStage();
                        }
                        else
                        {
                            switch (_state)
                            {
                            case State.NotifiedWhenQuerying:
                                // maybe we missed some new event when querying, retry
                                _state = State.Idle;
                                Query();
                                break;

                            case State.Querying:
                                if (_live)
                                {
                                    // nothing new, wait for notification
                                    _state = State.WaitingForNotification;
                                }
                                else
                                {
                                    // not a live stream, nothing else currently in the database, close the stream
                                    CompleteStage();
                                }
                                break;

                            default:
                                Log.Error($"Unexpected source state: {_state}");
                                FailStage(new IllegalStateException($"Unexpected source state: {_state}"));
                                break;
                            }
                        }
                    }
                    else
                    {
                        var(evts, maxSequenceNr) = events.Aggregate((new List <EventEnvelope>(), _currentSequenceNr), (tuple, pr) =>
                        {
                            if (!pr.IsDeleted &&
                                pr.SequenceNr >= _currentSequenceNr &&
                                pr.SequenceNr <= _toSequenceNr)
                            {
                                tuple.Item1.Add(new EventEnvelope(new Sequence(pr.SequenceNr), pr.PersistenceId, pr.SequenceNr, pr.Payload));
                                tuple.Item2 = pr.SequenceNr + 1;
                            }
                            else
                            {
                                tuple.Item2 = pr.SequenceNr + 1;
                            }

                            return(tuple);
                        });

                        _currentSequenceNr = maxSequenceNr;
                        Log.Debug($"Max sequence number is now {maxSequenceNr}");
                        if (evts.Count > 0)
                        {
                            evts.ForEach(_buffer.Enqueue);
                            Deliver();
                        }
                        else
                        {
                            // requery immediately
                            _state = State.Idle;
                            Query();
                        }
                    }
                });

                if (_live)
                {
                    // subscribe to notification stream only if live stream was required
                    var messageCallback = GetAsyncCallback <(RedisChannel channel, string bs)>(data =>
                    {
                        if (data.channel.Equals(_journalHelper.GetJournalChannel(_persistenceId)))
                        {
                            Log.Debug("Message received");

                            switch (_state)
                            {
                            case State.Idle:
                                // do nothing, no query is running and no client request was performed
                                break;

                            case State.Querying:
                                _state = State.NotifiedWhenQuerying;
                                break;

                            case State.NotifiedWhenQuerying:
                                // do nothing we already know that some new events may exist
                                break;

                            case State.WaitingForNotification:
                                _state = State.Idle;
                                Query();
                                break;
                            }
                        }
                        else
                        {
                            Log.Debug($"Message from unexpected channel: {data.channel}");
                        }
                    });

                    _subscription = _redis.GetSubscriber();
                    _subscription.Subscribe(_journalHelper.GetJournalChannel(_persistenceId), (channel, value) =>
                    {
                        messageCallback.Invoke((channel, value));
                    });
                }
                else
                {
                    // start by first querying the current highest sequenceNr
                    // for the given persistent id
                    // stream will stop once this has been delivered
                    _state = State.Initializing;

                    var initCallback = GetAsyncCallback <long>(sn =>
                    {
                        if (_toSequenceNr > sn)
                        {
                            // the initially requested max sequence number is higher than the current
                            // one, restrict it to the current one
                            _toSequenceNr = sn;
                        }

                        switch (_state)
                        {
                        case State.QueryWhenInitializing:
                            // during initialization, downstream asked for an element,
                            // let’s query elements
                            _state = State.Idle;
                            Query();
                            break;

                        case State.Initializing:
                            // no request from downstream, just go idle
                            _state = State.Idle;
                            break;

                        default:
                            Log.Error($"Unexpected source state when initializing: {_state}");
                            FailStage(new IllegalStateException($"Unexpected source state when initializing: {_state}"));
                            break;
                        }
                    });

                    _redis.GetDatabase(_database).StringGetAsync(_journalHelper.GetHighestSequenceNrKey(_persistenceId)).ContinueWith(task =>
                    {
                        if (!task.IsCanceled || task.IsFaulted)
                        {
                            if (task.Result.IsNull == true)
                            {
                                // not found, close
                                CompleteStage();
                            }
                            else
                            {
                                initCallback(long.Parse(task.Result));
                            }
                        }
                        else
                        {
                            Log.Error(task.Exception, "Error while initializing current events by persistent id");
                            FailStage(task.Exception);
                        }
                    });
                }
            }
Exemplo n.º 2
0
        public override async Task <long> ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr)
        {
            var highestSequenceNr = await Database.StringGetAsync(_journalHelper.GetHighestSequenceNrKey(persistenceId));

            return(highestSequenceNr.IsNull ? 0L : (long)highestSequenceNr);
        }