/// <inheritdoc/> public async Task <SubscriptionResponse> HandleSubscription(SubscriptionId subscriptionId) { if (_subscriptions.TryGetConsentFor(subscriptionId, out var consentId)) { _logger.Trace("Already subscribed to subscription {SubscriptionId}", subscriptionId); return(new SuccessfulSubscriptionResponse(consentId)); } _logger.Trace("Getting microservice address"); if (!TryGetMicroserviceAddress(subscriptionId.ProducerMicroserviceId, out var microserviceAddress)) { var message = $"There is no microservice configuration for the producer microservice {subscriptionId.ProducerMicroserviceId}."; _logger.Warning(message); return(new FailedSubscriptionResponse(new Failure(SubscriptionFailures.MissingMicroserviceConfiguration, message))); } return(await _policy.Execute( async _ => { var client = CreateClient(microserviceAddress, _cancellationToken); var receivedResponse = await Subscribe(client, subscriptionId, microserviceAddress, _cancellationToken).ConfigureAwait(false); var response = HandleSubscriptionResponse(receivedResponse, client.ConnectResponse, subscriptionId); if (response.Success) { StartProcessingEventHorizon(response.ConsentId, subscriptionId, microserviceAddress, client); } return response; }, _cancellationToken).ConfigureAwait(false)); }
async Task <IProcessingResult> Process(CommittedEvent @event, CancellationToken cancellationToken) { _logger.Trace( "Processing Event {EventType} from Event Horizon in Scope {Scope} from Microservice {ProducerMicroservice} and Tenant {ProducerTenant}", @event.Type.Id, Scope, _subscriptionId.ProducerMicroserviceId, _subscriptionId.ProducerTenantId); await _policy.Execute( cancellationToken => _receivedEventsWriter.Write(@event, _consentId, Scope, cancellationToken), cancellationToken).ConfigureAwait(false); return(new SuccessfulProcessing()); }
Task Subscribe(TenantId consumer, Subscription subscription) => _policy.Execute( async(cancellationToken) => { _logger.Trace( "Attempting to subscribe to events from {Partition} in {Stream} of {ProducerTenant} in {Microservice} for {ConsumerTenant} into {Scope}", subscription.Partition, subscription.Stream, subscription.Tenant, subscription.Microservice, consumer, subscription.Scope); var response = await _subscriptions.Subscribe(consumer, subscription, cancellationToken).ConfigureAwait(false); if (!response.Success) { throw new FailedToSubscribeToEventHorizon( response.Failure.Reason, consumer, subscription.Microservice, subscription.Tenant, subscription.Stream, subscription.Partition); } else { _logger.Debug( "Successfully subscribed to events from {Partition} in {Stream} of {ProducerTenant} in {Microservice} for {ConsumerTenant} into {Scope} approved by {Consent}", subscription.Partition, subscription.Stream, subscription.Tenant, subscription.Microservice, consumer, subscription.Scope, response.Consent); } }, CancellationToken.None);
/// <inheritdoc/> public Task Persist(IStreamProcessorId streamProcessorId, IStreamProcessorState streamProcessorState, CancellationToken cancellationToken) => _policy.Execute(cancellationToken => _repository.Persist(streamProcessorId, streamProcessorState, cancellationToken), cancellationToken);
/// <inheritdoc/> public async Task <IStreamProcessorState> CatchupFor( IStreamProcessorId streamProcessorId, StreamProcessorState streamProcessorState, CancellationToken cancellationToken) { if (streamProcessorState.FailingPartitions.Count > 0) { streamProcessorState = (await _streamProcessorStates.TryGetFor(streamProcessorId, cancellationToken) .ConfigureAwait(false)).Result as StreamProcessorState; } var failingPartitionsList = streamProcessorState.FailingPartitions.ToList(); foreach (var kvp in failingPartitionsList) { var partition = kvp.Key; var failingPartitionState = kvp.Value; if (ShouldRetryProcessing(failingPartitionState)) { while (ShouldProcessNextEventInPartition(failingPartitionState.Position, streamProcessorState.Position)) { var tryGetEvent = await _eventsFetcherPolicy.Execute( cancellationToken => _eventsFromStreamsFetcher.FetchInPartition(partition, failingPartitionState.Position, cancellationToken), cancellationToken).ConfigureAwait(false); if (!tryGetEvent.Success) { break; } var streamEvent = tryGetEvent.Result; if (streamEvent.Partition != partition) { throw new StreamEventInWrongPartition(streamEvent, partition); } if (!ShouldProcessNextEventInPartition(streamEvent.Position, streamProcessorState.Position)) { break; } if (!ShouldRetryProcessing(failingPartitionState)) { break; } var processingResult = await RetryProcessingEvent( failingPartitionState, streamEvent.Event, partition, cancellationToken).ConfigureAwait(false); if (processingResult.Succeeded) { (streamProcessorState, failingPartitionState) = await ChangePositionInFailingPartition( streamProcessorId, streamProcessorState, partition, streamEvent.Position + 1, failingPartitionState.LastFailed, cancellationToken).ConfigureAwait(false); } else if (processingResult.Retry) { (streamProcessorState, failingPartitionState) = await SetFailingPartitionState( streamProcessorId, streamProcessorState, partition, failingPartitionState.ProcessingAttempts + 1, processingResult.RetryTimeout, processingResult.FailureReason, streamEvent.Position, DateTimeOffset.UtcNow, cancellationToken).ConfigureAwait(false); } else { (streamProcessorState, failingPartitionState) = await SetFailingPartitionState( streamProcessorId, streamProcessorState, partition, failingPartitionState.ProcessingAttempts + 1, DateTimeOffset.MaxValue, processingResult.FailureReason, streamEvent.Position, DateTimeOffset.UtcNow, cancellationToken).ConfigureAwait(false); } } if (ShouldRetryProcessing(failingPartitionState)) { streamProcessorState = await RemoveFailingPartition(streamProcessorId, streamProcessorState, partition, cancellationToken).ConfigureAwait(false); } } } return(streamProcessorState); }
/// <summary> /// Fetches the Event that is should be processed next. /// </summary> /// <param name="currentState">The current <see cref="IStreamProcessorState" />.</param> /// <param name="cancellationToken">The <see cref="CancellationToken" />.</param> /// <returns>A <see cref="Task" /> that, when resolved, returns the <see cref="StreamEvent" />.</returns> protected Task <StreamEvent> FetchNextEventToProcess(IStreamProcessorState currentState, CancellationToken cancellationToken) => _fetchEventToProcessPolicy.Execute(cancellationToken => _eventsFetcher.Fetch(currentState.Position, cancellationToken), cancellationToken);