/// <inheritdoc /> public async Task <ScopedFilterStreamProcessor> Create( TypeFilterWithEventSourcePartitionDefinition filterDefinition, StreamProcessorId streamProcessorId, CancellationToken cancellationToken) { var processorState = await GetOrCreateStreamProcessorState( streamProcessorId, StreamProcessorState.New, cancellationToken) .ConfigureAwait(false); if (processorState is not StreamProcessorState unpartitionedProcessorState) { throw new ExpectedUnpartitionedStreamProcessorState(streamProcessorId); } // TODO: This is not needed when using the fast event handler. NotifyStream(streamProcessorId.ScopeId, filterDefinition, processorState.Position); return(_createFilterStreamProcessor( _eventLogStream.Subscribe( streamProcessorId.ScopeId, processorState.Position.Value, new ReadOnlyCollection <ArtifactId>(filterDefinition.Types.ToList()), CancellationToken.None), streamProcessorId, filterDefinition.Partitioned, unpartitionedProcessorState)); }
/// <summary> /// Converts the <see cref="IFilterDefinition" /> to <see cref="AbstractFilterDefinition" />. /// </summary> /// <param name="filterDefinition">The <see cref="IFilterDefinition" />.</param> /// <returns>Converted <see cref="AbstractFilterDefinition" />.</returns> public static AbstractFilterDefinition ToStoreRepresentation(this IFilterDefinition filterDefinition) { return(filterDefinition switch { TypeFilterWithEventSourcePartitionDefinition definition => new TypePartitionFilterDefinition(definition.Types.Select(_ => _.Value)), PublicFilterDefinition => new RemoteFilterDefinition(), FilterDefinition => new RemoteFilterDefinition(), _ => throw new UnsupportedFilterDefinitionType(filterDefinition) });
void NotifyStream(ScopeId scopeId, TypeFilterWithEventSourcePartitionDefinition filterDefinition, StreamPosition position) { if (position == StreamPosition.Start) { return; } if (filterDefinition.Public) { _streamWatcher.NotifyForEvent(filterDefinition.TargetStream, position - 1); } else { _streamWatcher.NotifyForEvent(scopeId, filterDefinition.TargetStream, position - 1); } }
/// <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); } }