Ejemplo n.º 1
0
        // Not thread safe.
        public async Task ManageAsync(CancellationToken cancellationToken)
        {
            try
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    ResolutionStreamEvent resolutionStreamEvent;
                    while (!cancellationToken.IsCancellationRequested && _resolutionQueue.TryDequeue(out resolutionStreamEvent))
                    {
                        var            streamEvent   = resolutionStreamEvent.StreamEvent;
                        IBusinessEvent businessEvent = null;

                        try
                        {
                            // If unable to resolve event type then subscriber event will still be created but it
                            // will be unresolved.
                            if (_resolver.CanResolve(streamEvent.EventType))
                            {
                                businessEvent = _resolver.Resolve(streamEvent.EventType, streamEvent.Data);
                            }
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex, "Exception while resolving business event. Subscription event will be created with null business event.");
                        }


                        // Stream events may (and will for subscription streams) have links to original events.
                        // We want the original event as the core event and the subscription event info as secondary.
                        // However, if the event is not a link then we take the event info as both subscription info and original event.
                        var streamId             = streamEvent.StreamId;
                        var position             = streamEvent.Position;
                        var subscriptionStreamId = streamEvent.StreamId;
                        var subscriptionPosition = streamEvent.Position;
                        if (streamEvent.IsLink)
                        {
                            streamId = streamEvent.Link.StreamId;
                            position = streamEvent.Link.Position;
                        }
                        var subscriberEvent = new SubscriberEvent(resolutionStreamEvent.RegionId, streamId, position, subscriptionStreamId, subscriptionPosition, streamEvent.EventType, businessEvent);

                        // Send to the sorting manager.
                        await _sortingManager.ReceiveSubscriberEventAsync(subscriberEvent, cancellationToken);
                    }
                    await Task.WhenAny(new Task[] { _resolutionQueue.AwaitEnqueueSignalAsync(), cancellationToken.WaitHandle.AsTask() });
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Exception while managing resolution.");
                throw;
            }
        }
        public IBusinessEvent Resolve(string type, byte[] data)
        {
            var strongType = _typeNamesToStrongTypes[type];             // Allow to throw unhandled exception.

            try
            {
                var json = Encoding.Unicode.GetString(data);
                return((IBusinessEvent)JsonConvert.DeserializeObject(json, strongType));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Exception while resolving business event.");
                return(null);                // Intentionally resolve to null when serialization or encoding exception.
            }
        }
Ejemplo n.º 3
0
        // Not thread safe.
        public async Task ManageAsync(CancellationToken cancellationToken)
        {
            try
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    SubscriberEvent subscriberEvent;

                    while (!cancellationToken.IsCancellationRequested && _sortingQueue.TryDequeue(out subscriberEvent))
                    {
                        // Expecting a case INsensitive key used to group executions.
                        var parallelKey = _sorter.SortSubscriberEventToParallelKey(subscriberEvent);

                        if (string.IsNullOrEmpty(parallelKey))
                        {
                            throw new ArgumentException("Parallel key can't be null or empty.");
                        }

                        // Send to the handling manager.
                        await _handlingManager.ReceiveSubscriberEventAsync(parallelKey, subscriberEvent, cancellationToken);
                    }

                    await Task.WhenAny(new Task[] { _sortingQueue.AwaitEnqueueSignalAsync(), cancellationToken.WaitHandle.AsTask() });
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Exception while managing sorting.");
                throw;
            }
        }
Ejemplo n.º 4
0
        public async Task ResetStreamStatesAsync()
        {
            if (_isSubscribing)
            {
                throw new InvalidOperationException("Can't reset stream states while subscribing.");
            }

            try
            {
                await _streamStateRepo.ResetStreamStatesAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error while resetting stream states.");
                throw;
            }
        }
        public async Task LoadStreamEventsAsync(string streamId, long fromPosition, Func <StreamEvent, Task> receiverAsync, CancellationToken cancellationToken)
        {
            if (fromPosition < FirstPositionInStream)
            {
                throw new ArgumentException("Invalid position.");
            }

            try
            {
                StreamEventsSlice currentSlice;
                long nextSliceStart = StreamPosition.Start;

                do
                {
                    // Read stream with to-links resolution.
                    currentSlice = await _connection.ReadStreamEventsForwardAsync(streamId, nextSliceStart, _options.StreamReadBatchSize, true);

                    if (currentSlice.Status != SliceReadStatus.Success)
                    {
                        break;
                    }

                    nextSliceStart = currentSlice.NextEventNumber;

                    foreach (var resolvedEvent in currentSlice.Events)
                    {
                        await ReceiveResolvedEventAsync(receiverAsync, resolvedEvent, cancellationToken);
                    }
                } while (!currentSlice.IsEndOfStream && !cancellationToken.IsCancellationRequested);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Exception while loading stream.");
                throw;
            }
        }
Ejemplo n.º 6
0
        public virtual async Task <ICommandResult> HandleGenericCommandAsync(ICommand command, CancellationToken cancellationToken)
        {
            try
            {
                // Semantic validation to check format of fields, etc. - data that isn't dependent on state.
                var semanticValidationResult = command.ValidateSemantics();
                if (!semanticValidationResult.IsValid)
                {
                    return(CommandResult.FromErrors(semanticValidationResult.Errors.ToList()));
                }

                var regionId        = command.GetRegionId();
                var aggregateRootId = command.GetAggregateRootId();
                var streamId        = _streamIdBuilder.Build(regionId, _context, _aggregateRootName, aggregateRootId);

                // Load the latest aggregate root instance.
                var state = await _stateRepo.LoadAsync(regionId, streamId, cancellationToken);

                // Check for duplicate command id.
                if (await state.IsCausalIdInHistoryAsync(command.GetCommandId()))
                {
                    return(CommandResult.FromError("Duplicate command id."));
                }

                var handlerResult = await InvokeTypedCommandHandlerAsync(state, command, cancellationToken);

                if (!handlerResult.IsSuccess)
                {
                    return(handlerResult);
                }

                // Commit events to the agg root stream.
                if (!(await CommitEventsAsync(handlerResult.Events, regionId, streamId, state.StreamPositionCheckpoint)))
                {
                    return(CommandResult.FromError("Concurrency conflict while committing events."));
                }

                return(handlerResult);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Exception while handling generic command.");
                throw;
            }
        }
Ejemplo n.º 7
0
        private IEventStoreConnection CreateConnection(string regionId)
        {
            var uri        = _eventStoreUris[regionId];
            var builder    = ConnectionSettings.Create().KeepReconnecting();          // Very important. Attempt reconnect infinitely.
            var connection = EventStoreConnection.Create(uri, builder, $"Connection-{regionId}");

            connection.Connected += new EventHandler <ClientConnectionEventArgs>(delegate(Object o, ClientConnectionEventArgs a)
            {
                // _logger.LogDebug($"Event Store client connected. ({a.Connection.ConnectionName})");
            });

            connection.ErrorOccurred += new EventHandler <ClientErrorEventArgs>(delegate(Object o, ClientErrorEventArgs a)
            {
                _logger.LogError(a.Exception, $"Event store connection error. ({a.Connection.ConnectionName})");
            });

            _connections.Add(regionId, connection);
            return(connection);
        }
Ejemplo n.º 8
0
 // Thread safe, can be called in parallel by one caller to load events from multiple subscription sources.
 public async Task ListenAsync(string regionId, string subscriptionStreamId, CancellationToken cancellationToken)
 {
     try
     {
         using (var streamClient = _streamClientFactory.Create(regionId))
         {
             var listenerTask = streamClient.SubscribeToStreamAsync(
                 subscriptionStreamId, streamClient.FirstPositionInStream,
                 (se) => _resolutionManager.ReceiveStreamEventAsync(regionId, se, streamClient.FirstPositionInStream, cancellationToken),
                 cancellationToken
                 );
             await Task.WhenAny(new[] { listenerTask, cancellationToken.WaitHandle.AsTask() });
         }
     }
     catch (Exception ex)
     {
         _logger.LogError(ex, $"Exception while listening on regional subscription ({regionId}) stream {subscriptionStreamId}.");
         throw;
     }
 }
        public async Task TryRunHandlerAsync(SubscriberEvent subscriberEvent, CancellationToken cancellationToken)
        {
            try
            {
                try
                {
                    await _handler.HandleSubscriberEventAsync(subscriberEvent, cancellationToken);

                    await _streamStateRepo.SaveStreamStateAsync(subscriberEvent.StreamId, subscriberEvent.Position, false);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Exception while handling event. Stream will be halted until stream state errors are cleared.");

                    // Save errored stream state.
                    await _streamStateRepo.SaveStreamStateAsync(subscriberEvent.StreamId, subscriberEvent.Position, true);
                }
            }
            finally
            {
                _awaiter.ReleaseThrottle();                 // Make room for other handlers.
                _awaiter.SetHandlerCompletionSignal();
            }
        }
Ejemplo n.º 10
0
        // Not thread safe.
        public async Task ManageAsync(CancellationToken cancellationToken)
        {
            try
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    while (_handlingQueue.IsEventsAvailable)
                    {
                        _awaiter.ResetHandlerCompletionSignal();

                        // Clean up finished tasks.
                        _handlerTasks.PurgeFinishedTasks();

                        // Get the next event from the queue that isn't in a parallel group already running.
                        var item = _handlingQueue.TryDequeue(_handlerTasks.Keys);
                        if (item != null)
                        {
                            // When a stream has an error there may already be subscriber events in the
                            // handling queue that have made it past the first check for errored stream state
                            // prior to deserialization. If that's the case we just ignore the event.
                            var state = await _streamStateRepo.LoadStreamStateAsync(item.SubscriberEvent.StreamId);

                            if (state == null || !state.HasError)
                            {
                                await Task.WhenAny(new[] { _awaiter.AwaitThrottleAsync(), cancellationToken.WaitHandle.AsTask() });

                                if (!cancellationToken.IsCancellationRequested)
                                {
                                    _handlerTasks.Add(item.ParallelKey, _handlerRunner.TryRunHandlerAsync(item.SubscriberEvent, cancellationToken));
                                }
                            }
                        }
                        else
                        {
                            // Events are available but none in a parallel group that is not already executing.
                            // Wait for a new event to arrive or for an event handler to complete.
                            await Task.WhenAny(new Task[] {
                                _awaiter.AwaitHandlerCompletionSignalAsync(),
                                _handlingQueue.AwaitEnqueueSignalAsync(),
                                cancellationToken.WaitHandle.AsTask()
                            });
                        }

                        if (cancellationToken.IsCancellationRequested)
                        {
                            break;
                        }
                    }

                    if (cancellationToken.IsCancellationRequested)
                    {
                        break;
                    }

                    await Task.WhenAny(new Task[] { _handlingQueue.AwaitEnqueueSignalAsync(), cancellationToken.WaitHandle.AsTask() });
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Exception while managing handler execution.");
                throw;
            }
        }