private async Task AppendDeliveryMessage(DeliveryMetadata deliveryMetadata, string deliveryStreamId, string messageType, string eventDataJson, CancellationToken cancellationToken) { var jsonMeta = JsonConvert.SerializeObject(deliveryMetadata, SerializerSettings); var newStreamMessage = new NewStreamMessage(Guid.NewGuid(), messageType, eventDataJson, jsonMeta); await _streamStore.AppendToStream(deliveryStreamId, ExpectedVersion.Any, newStreamMessage, cancellationToken); }
public async Task DeliverNow(CancellationToken cancellationToken = default(CancellationToken)) { using (var cts = CancellationTokenSource.CreateLinkedTokenSource(_disposed.Token, cancellationToken)) { bool messageSent; do { messageSent = false; var webHooksToProcess = (await _webHooksRepository.Load(cancellationToken)) .Items.Where(w => w.Enabled).ToList(); foreach (var webHook in webHooksToProcess) { if (cts.Token.IsCancellationRequested) { return; } var streamIds = webHook.StreamIds; var nextMessageToDeliver = await GetNextMessageToDeliver(streamIds.OutStreamId, cts.Token); if (!nextMessageToDeliver.Found) { continue; } var streamMessageToDeliver = nextMessageToDeliver.StreamMessage; var previousDeliveryInfo = await GetPreviousDeliveryInfo(streamIds.DeliveriesStreamId, cancellationToken); if (!previousDeliveryInfo.Success && previousDeliveryInfo.EventId == streamMessageToDeliver.MessageId) { // Should we attempt to deliver? var timeSinceLastAttempt = _settings.GetUtcNow() - previousDeliveryInfo.DeliveryDateUtc; if (timeSinceLastAttempt > _settings.MaxDeliveryAttemptDuration) { var webHooks = await _webHooksRepository.Load(cancellationToken); webHooks.Disable(webHook.Id); } var delay = CalculateDelay(previousDeliveryInfo.DeliveryAttemptCount, _settings.MaxRetryDelay); if (_settings.GetUtcNow() - previousDeliveryInfo.DeliveryDateUtc < delay) { continue; } } // Forward the message to the subscriber. var jsonData = await streamMessageToDeliver.GetJsonData(cts.Token); var request = CreateSubscriberRequest(webHook, jsonData, streamMessageToDeliver, webHook.Secret); var response = await _httpClient.SendAsync(request, cts.Token); //TODO try-catch var deliveryMetadata = new DeliveryMetadata { AttemptCount = previousDeliveryInfo.DeliveryAttemptCount + 1, DeliverySuccess = true, EventId = streamMessageToDeliver.MessageId, Sequence = streamMessageToDeliver.StreamVersion }; if ((int)response.StatusCode > 299) { // Delivery failed, write error delivery message deliveryMetadata.DeliverySuccess = false; deliveryMetadata.ErrorMessage = $"Subscriber returned status code {response.StatusCode}"; await AppendDeliveryMessage( deliveryMetadata, streamIds.DeliveriesStreamId, streamMessageToDeliver.Type, jsonData, cancellationToken); } else { await AppendDeliveryMessage( deliveryMetadata, streamIds.DeliveriesStreamId, streamMessageToDeliver.Type, jsonData, cancellationToken); await _streamStore.SetStreamMetadata( streamIds.DeliveriesStreamId, ExpectedVersion.Any, maxCount : _settings.DeliveryStreamMaxCount, cancellationToken : cancellationToken); await _streamStore.DeleteMessage( streamIds.OutStreamId, streamMessageToDeliver.MessageId, cts.Token); messageSent = true; } } } while (messageSent); } }