Пример #1
0
        public void Subscribe(IEventConsumer eventConsumer)
        {
            Guard.NotNull(eventConsumer, nameof(eventConsumer));

            ThrowIfDisposed();

            if (timer != null)
            {
                return;
            }

            var consumerName    = eventConsumer.Name;
            var consumerStarted = false;

            timer = new CompletionTimer(5000, async ct =>
            {
                if (!consumerStarted)
                {
                    await eventConsumerInfoRepository.CreateAsync(consumerName);

                    consumerStarted = true;
                }

                try
                {
                    var status = await eventConsumerInfoRepository.FindAsync(consumerName);

                    var position = status.Position;

                    if (status.IsResetting)
                    {
                        currentSubscription?.Dispose();
                        currentSubscription = null;

                        position = null;

                        await ResetAsync(eventConsumer);
                    }
                    else if (status.IsStopped)
                    {
                        currentSubscription?.Dispose();
                        currentSubscription = null;

                        return;
                    }

                    if (currentSubscription == null)
                    {
                        await SubscribeAsync(eventConsumer, position);
                    }
                }
                catch (Exception ex)
                {
                    log.LogFatal(ex, w => w.WriteProperty("action", "EventHandlingFailed"));
                }
            });
        }
Пример #2
0
        public void Subscribe(IEventConsumer eventConsumer, int delay = 5000)
        {
            Guard.NotNull(eventConsumer, nameof(eventConsumer));

            ThrowIfDisposed();

            if (timer != null)
            {
                return;
            }

            var consumerName    = eventConsumer.Name;
            var consumerStarted = false;

            timer = new CompletionTimer(delay, async ct =>
            {
                if (!consumerStarted)
                {
                    await eventConsumerInfoRepository.CreateAsync(consumerName);

                    consumerStarted = true;
                }

                try
                {
                    var status = await eventConsumerInfoRepository.FindAsync(consumerName);

                    var position = status.Position;

                    if (status.IsResetting)
                    {
                        position = null;

                        await ResetAsync(eventConsumer, consumerName, position);
                    }
                    else if (status.IsStopped)
                    {
                        return;
                    }

                    await eventStore.GetEventsAsync(se =>
                    {
                        return(HandleEventAsync(eventConsumer, se, consumerName));
                    }, ct, eventConsumer.EventsFilter, position);
                }
                catch (Exception ex)
                {
                    log.LogFatal(ex, w => w.WriteProperty("action", "EventHandlingFailed"));

                    await eventConsumerInfoRepository.StopAsync(consumerName, ex.ToString());
                }
            });

            eventNotifier.Subscribe(timer.Trigger);
        }
        public EventConsumerActorTests()
        {
            consumerInfo.Position = Guid.NewGuid().ToString();
            consumerName          = eventConsumer.GetType().Name;

            A.CallTo(() => eventStore.CreateSubscription(A <IEventSubscriber> .Ignored, A <string> .Ignored, A <string> .Ignored)).Returns(eventSubscription);

            A.CallTo(() => eventConsumer.Name).Returns(consumerName);
            A.CallTo(() => eventConsumerInfoRepository.FindAsync(consumerName)).Returns(consumerInfo);

            A.CallTo(() => formatter.Parse(eventData, true)).Returns(envelope);

            sut = new EventConsumerActor(formatter, eventStore, eventConsumerInfoRepository, log)
            {
                ReconnectWaitMs = 0
            };

            sutActor      = sut;
            sutSubscriber = sut;
        }
Пример #4
0
        private async Task HandleAsync(object input)
        {
            try
            {
                if (!isStarted)
                {
                    await eventConsumerInfoRepository.CreateAsync(eventConsumer.Name);

                    isStarted = true;
                }

                var status = await eventConsumerInfoRepository.FindAsync(eventConsumer.Name);

                var lastReceivedEventNumber = status.LastHandledEventNumber;

                if (status.IsResetting)
                {
                    await ResetAsync();

                    Reset();
                }

                if (!status.IsStopped || !isRunning)
                {
                    var ct = new CancellationTokenSource();

                    await eventStore.GetEventsAsync(async storedEvent =>
                    {
                        if (!isRunning)
                        {
                            ct.Cancel();
                        }

                        var onEvent = OnEvent;

                        if (onEvent != null)
                        {
                            await onEvent(storedEvent);
                        }
                    }, ct.Token, null, lastReceivedEventNumber);
                }
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception ex)
            {
                OnError?.Invoke(ex);
            }
        }
Пример #5
0
        private async Task HandleSetupAsync(IEventConsumer consumer)
        {
            eventConsumer = consumer;

            var status = await eventConsumerInfoRepository.FindAsync(eventConsumer.Name);

            if (status != null)
            {
                statusError     = status.Error;
                statusPosition  = status.Position;
                statusIsRunning = !status.IsStopped;
            }

            if (statusIsRunning)
            {
                Subscribe(statusPosition);
            }
        }
Пример #6
0
        public EventReceiverTests()
        {
            var events = new[]
            {
                new StoredEvent("3", 3, eventData1),
                new StoredEvent("4", 4, eventData2),
                new StoredEvent("5", 5, eventData3)
            };

            consumerName = eventConsumer.GetType().Name;

            var eventStore = new MyEventStore(events);

            A.CallTo(() => eventConsumer.Name).Returns(consumerName);
            A.CallTo(() => eventConsumerInfoRepository.FindAsync(consumerName)).Returns(Task.FromResult <IEventConsumerInfo>(consumerInfo));

            A.CallTo(() => formatter.Parse(eventData1)).Returns(envelope1);
            A.CallTo(() => formatter.Parse(eventData2)).Returns(envelope2);
            A.CallTo(() => formatter.Parse(eventData3)).Returns(envelope3);

            sut = new EventReceiver(formatter, eventStore, eventConsumerInfoRepository, log);
        }
Пример #7
0
        private async Task OnMessage(object message)
        {
            if (isStopped)
            {
                return;
            }

            try
            {
                var oldStateId = stateId;
                var newStateId = stateId = Guid.NewGuid();

                switch (message)
                {
                case Teardown teardown:
                {
                    isStopped = true;

                    return;
                }

                case Setup setup:
                {
                    eventConsumer = setup.EventConsumer;

                    var status = await eventConsumerInfoRepository.FindAsync(eventConsumer.Name);

                    if (status != null)
                    {
                        statusError     = status.Error;
                        statusPosition  = status.Position;
                        statusIsRunning = !status.IsStopped;
                    }

                    if (statusIsRunning)
                    {
                        await SubscribeThisAsync(statusPosition);
                    }

                    break;
                }

                case StartConsumerMessage startConsumer:
                {
                    if (statusIsRunning)
                    {
                        return;
                    }

                    await SubscribeThisAsync(statusPosition);

                    statusError     = null;
                    statusIsRunning = true;

                    break;
                }

                case StopConsumerMessage stopConsumer:
                {
                    if (!statusIsRunning)
                    {
                        return;
                    }

                    await UnsubscribeThisAsync();

                    statusIsRunning = false;

                    break;
                }

                case ResetConsumerMessage resetConsumer:
                {
                    await UnsubscribeThisAsync();
                    await ClearAsync();
                    await SubscribeThisAsync(null);

                    statusError     = null;
                    statusPosition  = null;
                    statusIsRunning = true;

                    break;
                }

                case Reconnect reconnect:
                {
                    if (!statusIsRunning || reconnect.StateId != oldStateId)
                    {
                        return;
                    }

                    await SubscribeThisAsync(statusPosition);

                    break;
                }

                case SubscriptionFailed subscriptionFailed:
                {
                    if (subscriptionFailed.Subscription != eventSubscription)
                    {
                        return;
                    }

                    await UnsubscribeThisAsync();

                    if (retryWindow.CanRetryAfterFailure())
                    {
                        Task.Delay(ReconnectWaitMs).ContinueWith(t => dispatcher.SendAsync(new Reconnect {
                                StateId = newStateId
                            })).Forget();
                    }
                    else
                    {
                        throw subscriptionFailed.Exception;
                    }

                    break;
                }

                case SubscriptionEventReceived eventReceived:
                {
                    if (eventReceived.Subscription != eventSubscription)
                    {
                        return;
                    }

                    var @event = ParseEvent(eventReceived.Event);

                    await DispatchConsumerAsync(@event);

                    statusError    = null;
                    statusPosition = @eventReceived.Event.EventPosition;

                    break;
                }
                }

                await eventConsumerInfoRepository.SetAsync(eventConsumer.Name, statusPosition, !statusIsRunning, statusError);
            }
            catch (Exception ex)
            {
                try
                {
                    await UnsubscribeThisAsync();
                }
                catch (Exception unsubscribeException)
                {
                    ex = new AggregateException(ex, unsubscribeException);
                }

                log.LogFatal(ex, w => w
                             .WriteProperty("action", "HandleEvent")
                             .WriteProperty("state", "Failed")
                             .WriteProperty("eventConsumer", eventConsumer.Name));

                statusError     = ex.ToString();
                statusIsRunning = false;

                await eventConsumerInfoRepository.SetAsync(eventConsumer.Name, statusPosition, !statusIsRunning, statusError);
            }
        }