public Task <AckResult> HandleMessageTask(IHandledMessage message) { Interlocked.Increment(ref _received); while (!Block.WaitOne(500)) { } Interlocked.Increment(ref _handled); if (Guid.TryParse(message.Properties.MessageId, out var messageId) && message.Properties.Headers.TryGetValue("MessageGroupId", out var groupIdObj)) { var groupId = new Guid((byte[])groupIdObj); _messageGroupHandler.MessageHandled(groupId, messageId); } else { } return(Task.FromResult(AckResult.Ack)); }
public async Task <AckResult> HandleMessageTask(IHandledMessage message) { if (_cancellationToken.IsCancellationRequested) { return(AckResult.NackRequeue); } try { var bytes = message.Body; //note: This may not be the correct way to implement the FeatureCollection. In most of the available samples, //features are static and the HttpContext is customized so it can be manipulated directly within this method. //For the time being, this approach is very easy and provides better decoupling. When things get more complicated //we may revert to the other approach. //Typical webserver is a lot more complicated because it needs to handle the http protocol.HttpProtocol.ProcessRequests //and can handle multiple requests via the same connection. MsgNThen is entirely reliant on RabbitMQ client to handle all //such issues. //The Protocol can't directly access the HttpContext itself (which is really strange at first glance). Instead it implements //"IFeature"s that the HttpContext uses to implement its properties. var requestFeatures = new FeatureCollection(); var messageRequestFeature = new HttpRequestFeature { Path = $"/{message.RoutingKey}", //fix: use MemoryStream.WriteAsync(ReadOnlyMemory<Byte>) Body = new MemoryStream(bytes.ToArray()), Method = "GET", Headers = new HeaderDictionary(), }; if (message.Properties.Headers != null) { foreach (var property in message.Properties.Headers) { messageRequestFeature.Headers[property.Key] = property.Value?.ToString(); } } var groupInfo = GetMessageGroupInfo(message); messageRequestFeature.Headers[HeaderConstants.MessageId] = message.Properties.MessageId; messageRequestFeature.Headers[HeaderConstants.AppId] = message.Properties.AppId; messageRequestFeature.Headers[HeaderConstants.ReplyTo] = message.Properties.ReplyTo; messageRequestFeature.Headers[HeaderConstants.CorrelationId] = message.Properties.CorrelationId; //note: https://www.rabbitmq.com/validated-user-id.html messageRequestFeature.Headers[HeaderConstants.UserId] = message.Properties.UserId; messageRequestFeature.Headers.ContentLength = message.Body.Length; messageRequestFeature.Headers[HeaderNames.ContentType] = message.Properties.ContentType; var responseStream = new MemoryStream(); var responseBody = new StreamResponseBodyFeature(responseStream); var httpResponseFeature = new HttpResponseFeature() { Body = responseStream }; requestFeatures.Set <IHttpResponseBodyFeature>(responseBody); requestFeatures.Set <IHttpRequestFeature>(messageRequestFeature); requestFeatures.Set <IHttpResponseFeature>(httpResponseFeature); var context = _application.CreateContext(requestFeatures); await _application.ProcessRequestAsync(context); if (groupInfo != null) { _messageGroupHandler.MessageHandled(groupInfo.Value.messageGroupId, groupInfo.Value.messageId); } if (responseStream.Length > 0) { if (groupInfo != null) { //when the application populated the response we could either // - store this information so that the andThen processor can pick it up later or // - stream this request as data to the ReplyTo address for the same reason. //use Redis and S3 as result stores so that the final andThen can use the data collected from //those requests. } else { //since this isn't an andThen request, we should send this to the ReplyTo address //todo: XXXX implement result forwarding (using something like IAndThenMessageDeliverer) } //any/all of the above scenarios are handled by the following interface by using the //replyHandler to interpret the response and the message.Properties.ReplyTo address. } return(AckResult.Ack); } catch (Exception e) { _logger.LogError(e, "HandleMessageTask Failed"); return(AckResult.NackQuit); } }