Пример #1
0
    /// <inheritdoc/>
    public async Task <bool> TryPersist(ScopeId scopeId, IFilterDefinition filterDefinition, CancellationToken cancellationToken)
    {
        var tryGetStream = await _streamDefinitions.TryGet(scopeId, filterDefinition.TargetStream, cancellationToken).ConfigureAwait(false);

        if (!tryGetStream.Success)
        {
            return(false);
        }
        var newStreamDefinition = new StreamDefinition(filterDefinition);
        await _streamDefinitions.Persist(scopeId, newStreamDefinition, cancellationToken).ConfigureAwait(false);

        return(true);
    }
Пример #2
0
        async Task ValidateFilter <TFilterDefinition>(
            ScopeId scopeId,
            TFilterDefinition filterDefinition,
            Func <IFilterProcessor <TFilterDefinition> > getFilterProcessor,
            CancellationToken cancellationToken)
            where TFilterDefinition : IFilterDefinition
        {
            _logger.Debug("Validating Filter '{Filter}'", filterDefinition.TargetStream);
            var filterValidationResults = await _filterForAllTenants.Validate(getFilterProcessor, cancellationToken).ConfigureAwait(false);

            if (filterValidationResults.Any(_ => !_.Value.Succeeded))
            {
                var firstFailedValidation = filterValidationResults.Select(_ => _.Value).First(_ => !_.Succeeded);
                _logger.Warning("Filter validation failed. {Reason}", filterDefinition.TargetStream, firstFailedValidation.FailureReason);
                throw new FilterValidationFailed(filterDefinition.TargetStream, firstFailedValidation.FailureReason);
            }

            var filteredStreamDefinition = new StreamDefinition(filterDefinition);

            _logger.Debug("Persisting definition for Stream '{Stream}'", filteredStreamDefinition.StreamId);
            await _streamDefinitions.Persist(scopeId, filteredStreamDefinition, cancellationToken).ConfigureAwait(false);
        }
Пример #3
0
        /// <inheritdoc/>
        public override async Task Connect(
            IAsyncStreamReader <EventHandlerClientToRuntimeMessage> runtimeStream,
            IServerStreamWriter <EventHandlerRuntimeToClientMessage> clientStream,
            ServerCallContext context)
        {
            _logger.Debug("Connecting Event Handler");
            using var cts = CancellationTokenSource.CreateLinkedTokenSource(_hostApplicationLifetime.ApplicationStopping, context.CancellationToken);
            var cancellationToken = cts.Token;
            var dispatcher        = _reverseCallDispatchers.GetFor <EventHandlerClientToRuntimeMessage, EventHandlerRuntimeToClientMessage, EventHandlerRegistrationRequest, EventHandlerRegistrationResponse, HandleEventRequest, EventHandlerResponse>(
                runtimeStream,
                clientStream,
                context,
                _ => _.RegistrationRequest,
                (serverMessage, registrationResponse) => serverMessage.RegistrationResponse = registrationResponse,
                (serverMessage, request) => serverMessage.HandleRequest = request,
                _ => _.HandleResult,
                _ => _.CallContext,
                (request, context) => request.CallContext = context,
                _ => _.CallContext,
                (message, ping) => message.Ping = ping,
                message => message.Pong);

            _logger.Trace("Waiting for connection arguments...");
            if (!await dispatcher.ReceiveArguments(cancellationToken).ConfigureAwait(false))
            {
                const string message = "Event Handlers connection arguments were not received";
                _logger.Warning(message);
                var failure = new Failure(EventHandlersFailures.NoEventHandlerRegistrationReceived, message);
                await WriteFailedRegistrationResponse(dispatcher, failure, cancellationToken).ConfigureAwait(false);

                return;
            }

            _logger.Trace("Received connection arguments");
            var arguments        = dispatcher.Arguments;
            var executionContext = arguments.CallContext.ExecutionContext.ToExecutionContext();

            _logger.Trace("Setting execution context{NewLine}{ExecutionContext}", System.Environment.NewLine, executionContext);
            _executionContextManager.CurrentFor(executionContext);

            var sourceStream = StreamId.EventLog;

            _logger.Trace("Received Source Stream '{SourceStream}'", sourceStream);
            var eventHandlerId = arguments.EventHandlerId.To <EventProcessorId>();

            _logger.Trace("Received Event Handler '{EventHandler}'", eventHandlerId);
            StreamId targetStream = eventHandlerId.Value;
            var      scopeId      = arguments.ScopeId.To <ScopeId>();

            _logger.Trace("Received Scope '{Scope}'", scopeId);
            var types = arguments.Types_.Select(_ => _.Id.To <ArtifactId>());

            _logger.Trace("Received Types: [{Types}]'", string.Join(", ", types.Select(_ => $"'{_}'")));
            var partitioned = arguments.Partitioned;

            _logger.Trace("Event Handler '{EventHandler}' {PartitionedString}", eventHandlerId, partitioned ? "is partitioned" : "is not partitioned");
            if (targetStream.IsNonWriteable)
            {
                _logger.Warning("Cannot register Event Handler '{EventHandler}' because it is an invalid Stream Id", eventHandlerId);
                var failure = new Failure(
                    EventHandlersFailures.CannotRegisterEventHandlerOnNonWriteableStream,
                    $"Cannot register Event Handler: '{eventHandlerId}' because it is an invalid Stream Id");
                await WriteFailedRegistrationResponse(dispatcher, failure, cancellationToken).ConfigureAwait(false);

                return;
            }

            _logger.Debug("Connecting Event Handler '{EventHandlerId}'", eventHandlerId);
            var filterDefinition         = new TypeFilterWithEventSourcePartitionDefinition(sourceStream, targetStream, types, partitioned);
            var filteredStreamDefinition = new StreamDefinition(filterDefinition);
            Func <IFilterProcessor <TypeFilterWithEventSourcePartitionDefinition> > getFilterProcessor = () => new TypeFilterWithEventSourcePartition(
                scopeId,
                filterDefinition,
                _getEventsToStreamsWriter(),
                _loggerManager.CreateLogger <TypeFilterWithEventSourcePartition>());
            var tryRegisterFilterStreamProcessor = TryRegisterFilterStreamProcessor <TypeFilterWithEventSourcePartitionDefinition>(
                scopeId,
                eventHandlerId,
                getFilterProcessor,
                cancellationToken);

            if (!tryRegisterFilterStreamProcessor.Success)
            {
                if (tryRegisterFilterStreamProcessor.HasException)
                {
                    var exception = tryRegisterFilterStreamProcessor.Exception;
                    _logger.Warning(exception, "An error occurred while registering Event Handler '{EventHandlerId}'", eventHandlerId);
                    ExceptionDispatchInfo.Capture(exception).Throw();
                }
                else
                {
                    _logger.Debug("Failed to register Event Handler '{EventHandlerId}'. Filter already registered", eventHandlerId);
                    var failure = new Failure(
                        FiltersFailures.FailedToRegisterFilter,
                        $"Failed to register Event Handler: {eventHandlerId}. Filter already registered.");
                    await WriteFailedRegistrationResponse(dispatcher, failure, cancellationToken).ConfigureAwait(false);

                    return;
                }
            }

            using var filterStreamProcessor = tryRegisterFilterStreamProcessor.Result;

            var tryRegisterEventProcessorStreamProcessor = TryRegisterEventProcessorStreamProcessor(
                scopeId,
                eventHandlerId,
                filteredStreamDefinition,
                () => new EventProcessor(
                    scopeId,
                    eventHandlerId,
                    dispatcher,
                    _loggerManager.CreateLogger <EventProcessor>()),
                cancellationToken);

            if (!tryRegisterEventProcessorStreamProcessor.Success)
            {
                if (tryRegisterEventProcessorStreamProcessor.HasException)
                {
                    var exception = tryRegisterEventProcessorStreamProcessor.Exception;
                    _logger.Warning(exception, "An error occurred while registering Event Handler' {EventHandlerId}", eventHandlerId);
                    ExceptionDispatchInfo.Capture(exception).Throw();
                }
                else
                {
                    _logger.Warning("Failed to register Event Handler: {eventHandlerId}. Event Processor already registered on Source Stream '{SourceStreamId}'", eventHandlerId, eventHandlerId);
                    var failure = new Failure(
                        FiltersFailures.FailedToRegisterFilter,
                        $"Failed to register Event Handler: {eventHandlerId}. Event Processor already registered on Source Stream: '{eventHandlerId}'");
                    await WriteFailedRegistrationResponse(dispatcher, failure, cancellationToken).ConfigureAwait(false);

                    return;
                }
            }

            using var eventProcessorStreamProcessor = tryRegisterEventProcessorStreamProcessor.Result;

            var tryStartEventHandler = await TryStartEventHandler(
                dispatcher,
                filterStreamProcessor,
                eventProcessorStreamProcessor,
                scopeId,
                filterDefinition,
                getFilterProcessor,
                cancellationToken).ConfigureAwait(false);

            if (!tryStartEventHandler.Success)
            {
                cts.Cancel();
                if (tryStartEventHandler.HasException)
                {
                    var exception = tryStartEventHandler.Exception;
                    _logger.Debug(exception, "An error occurred while starting Event Handler '{EventHandlerId}' in Scope {ScopeId}", eventHandlerId, scopeId);
                    ExceptionDispatchInfo.Capture(exception).Throw();
                }
                else
                {
                    _logger.Warning("Could not start Event Handler '{EventHandlerId}' in Scope: {ScopeId}", eventHandlerId, scopeId);
                    return;
                }
            }

            var tasks = tryStartEventHandler.Result;

            try
            {
                await Task.WhenAny(tasks).ConfigureAwait(false);

                if (TryGetException(tasks, out var ex))
                {
                    _logger.Warning(ex, "An error occurred while running Event Handler '{EventHandlerId}' in Scope: '{ScopeId}'", eventHandlerId, scopeId);
                    ExceptionDispatchInfo.Capture(ex).Throw();
                }
            }
            finally
            {
                cts.Cancel();
                await Task.WhenAll(tasks).ConfigureAwait(false);

                _logger.Debug("Event Handler: '{EventHandler}' in Scope: '{ScopeId}' disconnected", eventHandlerId, scopeId);
            }
        }
    async Task <FilterValidationResult> PerformValidation(IFilterProcessor <IFilterDefinition> filter, StreamPosition lastUnprocessedEvent, CancellationToken cancellationToken)
    {
        try
        {
            var streamDefinition       = new StreamDefinition(filter.Definition);
            var oldStreamEventsFetcher = await _eventFetchers.GetRangeFetcherFor(
                filter.Scope,
                streamDefinition,
                cancellationToken).ConfigureAwait(false);

            var eventLogFetcher = await _eventFetchers.GetRangeFetcherFor(
                filter.Scope,
                new EventLogStreamDefinition(),
                cancellationToken).ConfigureAwait(false);

            var oldStream = oldStreamEventsFetcher.FetchRange(
                new StreamPositionRange(StreamPosition.Start, ulong.MaxValue),
                cancellationToken);
            var eventLogStream = eventLogFetcher.FetchRange(new StreamPositionRange(StreamPosition.Start, lastUnprocessedEvent), cancellationToken);
            await using var oldStreamEnumerator = oldStream.GetAsyncEnumerator(cancellationToken);
            var newStreamPosition = 0;
            await foreach (var eventFromEventLog in eventLogStream.WithCancellation(cancellationToken))
            {
                var filteringResult = await filter.Filter(eventFromEventLog.Event, PartitionId.None, filter.Identifier, eventFromEventLog.Event.ExecutionContext, cancellationToken).ConfigureAwait(false);

                if (filteringResult is FailedFiltering failedResult)
                {
                    return(FilterValidationResult.Failed(failedResult.FailureReason));
                }

                if (!filteringResult.IsIncluded)
                {
                    continue;
                }

                if (!await oldStreamEnumerator.MoveNextAsync())
                {
                    return(FilterValidationResult.Failed("The number of events included in the new stream generated from the filter does not match the old stream."));
                }
                var oldStreamEvent = oldStreamEnumerator.Current;
                var filteredEvent  = new StreamEvent(
                    eventFromEventLog.Event,
                    new StreamPosition((ulong)newStreamPosition++),
                    filter.Definition.TargetStream,
                    filteringResult.Partition,
                    streamDefinition.Partitioned);
                if (EventsAreNotEqual(filter.Definition, filteredEvent, oldStreamEvent, out var failedValidation))
                {
                    return(failedValidation);
                }
            }

            if (await oldStreamEnumerator.MoveNextAsync())
            {
                return(FilterValidationResult.Failed($"The number of events included in the new stream generated from the filter does not match the old stream."));
            }

            return(FilterValidationResult.Succeeded());
        }
        catch (Exception exception)
        {
            return(FilterValidationResult.Failed(exception.Message));
        }
    }