public async Task <MessageRoute> RouteForDestination(Envelope envelope) { envelope.Destination = _lookup.Resolve(envelope.Destination); var messageType = envelope.Message.GetType(); var routes = await Route(messageType); var candidate = routes.FirstOrDefault(x => x.MatchesEnvelope(envelope)); if (candidate != null) { return(candidate); } var modelWriter = _serializers.WriterFor(messageType); var contentType = envelope.ContentType ?? envelope.AcceptedContentTypes.Intersect(modelWriter.ContentTypes).FirstOrDefault() ?? "application/json"; var channel = _channels.GetOrBuildChannel(envelope.Destination); return(new MessageRoute( messageType, modelWriter, channel, contentType)); }
private async Task <int> recoverFrom(Uri destination, IDocumentSession session) { try { var channel = _channels.GetOrBuildChannel(destination); if (channel.Latched) { return(0); } var outgoing = await session.Connection.CreateCommand(_findOutgoingEnvelopesSql) .With("destination", destination.ToString(), NpgsqlDbType.Varchar) .ExecuteToEnvelopes(); var filtered = filterExpired(session, outgoing); // Might easily try to do this in the time between starting // and having the data fetched. Was able to make that happen in // (contrived) testing if (channel.Latched || !filtered.Any()) { return(0); } session.MarkOwnership(_marker.Outgoing, _marker.CurrentNodeId, filtered); await session.SaveChangesAsync(); _logger.RecoveredOutgoing(filtered); foreach (var envelope in filtered) { try { await channel.QuickSend(envelope); } catch (Exception e) { _logger.LogException(e, message: $"Unable to enqueue {envelope} for sending"); } } return(outgoing.Count()); } catch (UnknownTransportException e) { _logger.LogException(e, message: $"Could not resolve a channel for {destination}"); await DeleteFromOutgoingEnvelopes(session, TransportConstants.AnyNode, destination); await session.SaveChangesAsync(); return(0); } }
public Task Enqueue <T>(T message) { var isDurable = _settings.Workers.ShouldBeDurable(typeof(T)); var uri = isDurable ? TransportConstants.DurableLoopbackUri : TransportConstants.LoopbackUri; var channel = _channels.GetOrBuildChannel(uri); var envelope = new Envelope(message); return(channel.Send(envelope)); }
private Envelope buildAcknowledgement() { var ack = new Envelope { ParentId = Envelope.Id, Destination = Envelope.ReplyUri, ResponseId = Envelope.Id, SagaId = Envelope.SagaId, Message = new Acknowledgement { CorrelationId = Envelope.Id }, Route = new MessageRoute(typeof(Acknowledgement), Envelope.ReplyUri, "application/json") { Channel = _channels.GetOrBuildChannel(Envelope.ReplyUri), }, Writer = _serialization.JsonWriterFor(typeof(Acknowledgement)) }; return(ack); }
private async Task <int> recoverFrom(Uri destination, SqlConnection conn) { try { Envelope[] filtered = null; List <Envelope> outgoing = null; if (_channels.GetOrBuildChannel(destination).Latched) { return(0); } var tx = conn.BeginTransaction(); try { outgoing = await conn.CreateCommand(tx, _findOutgoingEnvelopesSql) .With("destination", destination.ToString(), SqlDbType.VarChar) .ExecuteToEnvelopes(); filtered = await filterExpired(conn, tx, outgoing); // Might easily try to do this in the time between starting // and having the data fetched. Was able to make that happen in // (contrived) testing if (_channels.GetOrBuildChannel(destination).Latched || !filtered.Any()) { tx.Rollback(); return(0); } await markOwnership(conn, tx, filtered); tx.Commit(); } catch (Exception) { tx.Rollback(); throw; } _logger.RecoveredOutgoing(filtered); foreach (var envelope in filtered) { try { await _channels.GetOrBuildChannel(destination).QuickSend(envelope); } catch (Exception e) { _logger.LogException(e, message: $"Unable to enqueue {envelope} for sending"); } } return(outgoing.Count()); } catch (UnknownTransportException e) { _logger.LogException(e, message: $"Could not resolve a channel for {destination}"); var tx = conn.BeginTransaction(); await DeleteFromOutgoingEnvelopes(conn, TransportConstants.AnyNode, destination, tx); tx.Commit(); return(0); } }