public EventConsumerGrainTests()
        {
            state.Position = initialPosition;

            consumerName = eventConsumer.GetType().Name;

            A.CallTo(() => store.WithSnapshots(A <Type> .Ignored, consumerName, A <Func <EventConsumerState, Task> > .Ignored))
            .Invokes(new Action <Type, string, Func <EventConsumerState, Task> >((t, key, a) =>
            {
                apply = a;
            }))
            .Returns(persistence);

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

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

            A.CallTo(() => persistence.ReadAsync(EtagVersion.Any))
            .Invokes(new Action <long>(s => apply(state)));

            A.CallTo(() => persistence.WriteSnapshotAsync(A <EventConsumerState> .Ignored))
            .Invokes(new Action <EventConsumerState>(s => state = s));

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

            sut = new MyEventConsumerGrain(
                x => eventConsumer,
                store,
                eventStore,
                formatter,
                log);
        }
        public EventConsumerGrainTests()
        {
            grainState.Value.Position = initialPosition;

            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(() => eventConsumer.Handles(A <StoredEvent> .Ignored))
            .Returns(true);

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

            sut = new MyEventConsumerGrain(
                x => eventConsumer,
                grainState,
                eventStore,
                formatter,
                log);
        }
Beispiel #3
0
        public BatchSubscriber(
            EventConsumerGrain grain,
            IEventDataFormatter eventDataFormatter,
            IEventConsumer eventConsumer,
            Func <IEventSubscriber, IEventSubscription> factory,
            TaskScheduler scheduler)
        {
            this.eventDataFormatter = eventDataFormatter;

            var batchSize  = Math.Max(1, eventConsumer !.BatchSize);
            var batchDelay = Math.Max(100, eventConsumer.BatchDelay);

            var parse = new TransformBlock <Job, Job>(job =>
            {
                if (job.StoredEvent != null)
                {
                    job.ShouldHandle = eventConsumer.Handles(job.StoredEvent);
                }

                if (job.ShouldHandle)
                {
                    try
                    {
                        job.Event = ParseKnownEvent(job.StoredEvent !);
                    }
                    catch (Exception ex)
                    {
                        job.Exception = ex;
                    }
                }

                return(job);
            }, new ExecutionDataflowBlockOptions
            {
                BoundedCapacity        = batchSize,
                MaxDegreeOfParallelism = 1,
                MaxMessagesPerTask     = 1
            });

            var buffer = AsyncHelper.CreateBatchBlock <Job>(batchSize, batchDelay, new GroupingDataflowBlockOptions
            {
                BoundedCapacity = batchSize * 2
            });

            var handle = new ActionBlock <IList <Job> >(async jobs =>
            {
                foreach (var jobsBySender in jobs.GroupBy <Job, object>(x => x.Sender))
                {
                    var sender = jobsBySender.Key;

                    if (ReferenceEquals(sender, eventSubscription.Sender))
                    {
                        var exception = jobs.FirstOrDefault(x => x.Exception != null)?.Exception;

                        if (exception != null)
                        {
                            await grain.OnErrorAsync(Sender, exception);
                        }
                        else
                        {
                            await grain.OnEventsAsync(Sender, GetEvents(jobsBySender), GetPosition(jobsBySender));
                        }
                    }
                }
            },
                                                        new ExecutionDataflowBlockOptions
            {
                BoundedCapacity        = 2,
                MaxDegreeOfParallelism = 1,
                MaxMessagesPerTask     = 1,
                TaskScheduler          = scheduler
            });

            parse.LinkTo(buffer, new DataflowLinkOptions
            {
                PropagateCompletion = true
            });

            buffer.LinkTo(handle, new DataflowLinkOptions
            {
                PropagateCompletion = true
            });

            pipelineStart = parse;
            pipelineEnd   = handle;

            eventSubscription = factory(this);
        }