async Task <bool> Subscribe( IReverseCallClient <EventHorizonConsumerToProducerMessage, EventHorizonProducerToConsumerMessage, ConsumerSubscriptionRequest, Contracts.SubscriptionResponse, ConsumerRequest, ConsumerResponse> reverseCallClient, SubscriptionId subscriptionId, MicroserviceAddress microserviceAddress, CancellationToken cancellationToken) { _logger.Debug( "Tenant '{ConsumerTenantId}' is subscribing to events from tenant '{ProducerTenantId}' in microservice '{ProducerMicroserviceId}' on address '{Host}:{Port}'", subscriptionId.ConsumerTenantId, subscriptionId.ProducerTenantId, subscriptionId.ProducerMicroserviceId, microserviceAddress.Host, microserviceAddress.Port); var tryGetStreamProcessorState = await _streamProcessorStates.TryGetFor(subscriptionId, cancellationToken).ConfigureAwait(false); var publicEventsPosition = tryGetStreamProcessorState.Result?.Position ?? StreamPosition.Start; return(await reverseCallClient.Connect( new ConsumerSubscriptionRequest { PartitionId = subscriptionId.PartitionId.ToProtobuf(), StreamId = subscriptionId.StreamId.ToProtobuf(), StreamPosition = publicEventsPosition.Value, TenantId = subscriptionId.ProducerTenantId.ToProtobuf() }, cancellationToken).ConfigureAwait(false)); }
void StartProcessingEventHorizon( ConsentId consentId, SubscriptionId subscriptionId, MicroserviceAddress microserviceAddress, IReverseCallClient <EventHorizonConsumerToProducerMessage, EventHorizonProducerToConsumerMessage, ConsumerSubscriptionRequest, Contracts.SubscriptionResponse, ConsumerRequest, ConsumerResponse> reverseCallClient) { Task.Run(async() => { try { await ReadEventsFromEventHorizon(consentId, subscriptionId, reverseCallClient).ConfigureAwait(false); throw new Todo(); // TODO: This is a hack to get the policy going. Remove this when we can have policies on return values } catch (Exception ex) { _logger.Debug(ex, "Reconnecting to event horizon with subscription {subscriptionId}", subscriptionId); await _policy.Execute( async _ => { reverseCallClient = CreateClient(microserviceAddress, _cancellationToken); var receivedResponse = await Subscribe(reverseCallClient, subscriptionId, microserviceAddress, _cancellationToken).ConfigureAwait(false); var response = HandleSubscriptionResponse(receivedResponse, reverseCallClient.ConnectResponse, subscriptionId); if (!response.Success) { throw new Todo(); // TODO: This is a hack to get the policy going. Remove this when we can have policies on return values } await ReadEventsFromEventHorizon(response.ConsentId, subscriptionId, reverseCallClient).ConfigureAwait(false); throw new Todo(); // TODO: This is a hack to get the policy going. Remove this when we can have policies on return values }, _cancellationToken).ConfigureAwait(false); } }); }
async Task ReadEventsFromEventHorizon( ConsentId consentId, SubscriptionId subscriptionId, IReverseCallClient <EventHorizonConsumerToProducerMessage, EventHorizonProducerToConsumerMessage, ConsumerSubscriptionRequest, Contracts.SubscriptionResponse, ConsumerRequest, ConsumerResponse> reverseCallClient) { _logger.Information("Successfully connected event horizon with {subscriptionId}. Waiting for events to process", subscriptionId); var queue = new AsyncProducerConsumerQueue <StreamEvent>(); var eventsFetcher = new EventsFromEventHorizonFetcher(queue); using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_cancellationToken); var tasks = new List <Task>(); try { _subscriptions.TrySubscribe( consentId, subscriptionId, new EventProcessor(consentId, subscriptionId, _eventHorizonEventsWriter, _eventProcessorPolicy, _logger), eventsFetcher, linkedTokenSource.Token, out var outputtedStreamProcessor); using var streamProcessor = outputtedStreamProcessor; await streamProcessor.Initialize().ConfigureAwait(false); tasks.Add(Task.Run(async() => { await reverseCallClient.Handle( (request, cancellationToken) => HandleConsumerRequest(subscriptionId, queue, request, cancellationToken), linkedTokenSource.Token).ConfigureAwait(false); linkedTokenSource.Cancel(); })); tasks.Add(streamProcessor.Start()); } catch (Exception ex) { linkedTokenSource.Cancel(); _logger.Warning(ex, "Error occurred while initializing Subscription: {subscriptionId}", subscriptionId); return; } var finishedTask = await Task.WhenAny(tasks).ConfigureAwait(false); if (!linkedTokenSource.IsCancellationRequested) { linkedTokenSource.Cancel(); } if (TryGetException(tasks, out var exception)) { linkedTokenSource.Cancel(); _logger.Warning(exception, "Error occurred while processing Subscription: {subscriptionId}", subscriptionId); } await Task.WhenAll(tasks).ConfigureAwait(false); }
/// <summary> /// Initializes a new instance of the <see cref="EventHorizonConnection" /> class. /// </summary> /// <param name="executionContext">The <see cref="ExecutionContext"/>.</param> /// <param name="reverseCallClient">The reverse call client.</param> /// <param name="metrics">The system for collecting metrics.</param> /// <param name="logger">The logger.</param> public EventHorizonConnection( ExecutionContext executionContext, IReverseCallClient <ConsumerSubscriptionRequest, Contracts.SubscriptionResponse, ConsumerRequest, ConsumerResponse> reverseCallClient, IMetricsCollector metrics, ILogger logger) { _executionContext = executionContext; _reverseCallClient = reverseCallClient; _metrics = metrics; _logger = logger; }