Пример #1
0
        public async Task WriteAsync(string topicName, string servicePath, HttpContext httpContext)
        {
            var gateConsumer = _gateTemporaryConsumers.GetOrAdd(topicName, _ =>
            {
                var serviceName = Guid.NewGuid().ToString();
                return(_gateFactory.CreateConsumer <GateRequest, GateResponse>(serviceName, topicName,
                                                                               async(genericContext, cancellationToken) =>
                {
                    if (servicePath != genericContext.Message.ServicePath)
                    {
                        return;
                    }

                    var message = Encoding.UTF8.GetString(genericContext.Message.Content);
                    var messageParts = message.Split('\n');
                    if (_consumerContexts.TryGetValue(topicName, out var topicContexts))
                    {
                        foreach (var context in topicContexts.Values)
                        {
                            if (!string.IsNullOrEmpty(servicePath))
                            {
                                await context.Response.WriteAsync($"event: {servicePath}\n", cancellationToken);
                            }

                            foreach (var messagePart in messageParts)
                            {
                                await context.Response.WriteAsync($"data: {messagePart}\n", cancellationToken);
                            }

                            await context.Response.WriteAsync($"\n", cancellationToken);
                            await context.Response.Body.FlushAsync(cancellationToken);
                        }
                    }
                }, () => { }, true, 1));
            });
Пример #2
0
        public async Task Subscribe_Test()
        {
            var gateConsumer = A.Fake <IGateConsumer>();

            A.CallTo(() => _gateFactory.CreateConsumer("service-name", "topic-name",
                                                       A <Func <GateContext, CancellationToken, Task> > .Ignored, A <Action> .Ignored,
                                                       false, 10)).Returns(gateConsumer);

            var consumer = await _toTest.SubscribeConsumerAsync("service-name", "topic-name",
                                                                new Uri("http://test-host"),
                                                                10, 20, 30);

            Assert.AreEqual(new Uri("http://test-host"), consumer.Endpoint);
            Assert.AreEqual(gateConsumer, consumer.GateConsumer);
            Assert.AreEqual(20, consumer.RestartDelayInSeconds);
            Assert.AreEqual(30, consumer.RestartCount);
        }
Пример #3
0
        public static IGateConsumer CreateConsumer <TMessage, TReply>(
            this IGateFactory brokerFactory,
            string serviceName,
            string topicName,
            Func <GateContext <TMessage, TReply>, CancellationToken, Task> messageHandler,
            Action abortedHandler,
            bool autoDelete, int maxConcurrentMessages)
        {
            serviceName = serviceName ?? throw new ArgumentNullException(nameof(serviceName));
            topicName   = topicName ?? throw new ArgumentNullException(nameof(topicName));

            return(brokerFactory.CreateConsumer(serviceName, topicName, async(context, cancellationToken) =>
            {
                var genericContext = new GateContext <TMessage, TReply>(
                    message: Serializer.Deserialize <TMessage>(context.Message),
                    isRequest: context.IsRequest
                    );
                await messageHandler(genericContext, cancellationToken);
                if (genericContext.IsRequest)
                {
                    context.Reply = Serializer.Serialize(genericContext.Reply);
                }
            }, abortedHandler, autoDelete, maxConcurrentMessages));
        }
Пример #4
0
        public async Task <ProxyConsumer> SubscribeConsumerAsync(
            string serviceName,
            string topicName,
            Uri endpoint,
            int maxConcurrentMessages,
            int restartDelayInSeconds,
            int restartCount,
            CancellationToken cancellationToken = default)
        {
            serviceName = serviceName ?? throw new ArgumentNullException(nameof(serviceName));
            topicName   = topicName ?? throw new ArgumentNullException(nameof(topicName));
            endpoint    = endpoint ?? throw new ArgumentNullException(nameof(endpoint));
            if (!endpoint.IsAbsoluteUri)
            {
                throw new ArgumentException("Endpoint uri must be absolute", nameof(endpoint));
            }

            var consumerId = $"{serviceName}_{topicName}_{endpoint}".ToSha256();

            var proxyConsumer = new ProxyConsumer();

            if (!_proxyConsumers.TryAdd(consumerId, proxyConsumer))
            {
                throw new InvalidOperationException("Consumer already exists");
            }

            try
            {
                proxyConsumer.Id                          = consumerId;
                proxyConsumer.Endpoint                    = endpoint;
                proxyConsumer.AbortTime                   = null;
                proxyConsumer.RestartDelayInSeconds       = restartDelayInSeconds;
                proxyConsumer.RestartCount                = restartCount;
                proxyConsumer.HttpClient                  = _httpClientFactory.CreateClient();
                proxyConsumer.UnsubscribeCompletionSource = null;
                proxyConsumer.GateConsumer                = _gateFactory.CreateConsumer <GateRequest, GateResponse>(serviceName,
                                                                                                                    topicName, async(genericContext, ct) =>
                {
                    var httpRequestMessage  = genericContext.Message.ToHttpRequestMessage(endpoint);
                    var httpResponseMessage = await proxyConsumer.HttpClient.SendAsync(httpRequestMessage, ct);
                    if (!httpResponseMessage.IsSuccessStatusCode && !genericContext.IsRequest)
                    {
                        if (!_fallbackServices.Any())
                        {
                            httpResponseMessage.EnsureSuccessStatusCode();
                        }


                        var fallbackExceptions = new List <Exception>();
                        foreach (var fallbackService in _fallbackServices)
                        {
                            try
                            {
                                await fallbackService.SendAsync(serviceName, topicName, genericContext.Message, ct);
                                break;
                            }
                            catch (Exception ex)
                            {
                                fallbackExceptions.Add(ex);
                            }
                        }

                        if (fallbackExceptions.Any())
                        {
                            throw new AggregateException("Can not send message to service or fallbacks", fallbackExceptions);
                        }
                    }

                    if (genericContext.IsRequest)
                    {
                        genericContext.Reply = await httpResponseMessage.ToGateResponseAsync();
                    }
                }, () =>
                {
                    proxyConsumer.AbortTime = DateTime.Now;
                    if (proxyConsumer.UnsubscribeCompletionSource != null)
                    {
                        proxyConsumer.UnsubscribeCompletionSource.TrySetResult(true);
                    }
                    else
                    {
                        proxyConsumer.RestartCancellationTokenSource = new CancellationTokenSource();
                        proxyConsumer.RestartTask = RestartHandler(consumerId);
                    }
                }, false, maxConcurrentMessages);

                await proxyConsumer.GateConsumer.StartConsumeAsync(cancellationToken);

                return(proxyConsumer);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error starting consumer");
                _proxyConsumers.TryRemove(consumerId, out _);
                throw;
            }
        }