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); } }
private async Task <int> recoverFrom(Uri destination, IDurabilityAgentStorage storage) { try { Envelope[] filtered = null; Envelope[] outgoing = null; if (_runtime.GetOrBuildSendingAgent(destination).Latched) { return(0); } await storage.Session.Begin(); try { outgoing = await storage.Outgoing.Load(destination : destination); var expiredMessages = outgoing.Where(x => x.IsExpired()).ToArray(); _logger.DiscardedExpired(expiredMessages); await storage.Outgoing.Delete(expiredMessages.ToArray()); filtered = outgoing.Where(x => !expiredMessages.Contains(x)).ToArray(); // 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 (_runtime.GetOrBuildSendingAgent(destination).Latched || !filtered.Any()) { await storage.Session.Rollback(); return(0); } await storage.Outgoing.Reassign(_settings.UniqueNodeId, filtered); await storage.Session.Commit(); } catch (Exception) { await storage.Session.Rollback(); throw; } _logger.RecoveredOutgoing(filtered); foreach (var envelope in filtered) { try { await _runtime.GetOrBuildSendingAgent(destination).EnqueueOutgoing(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 storage.Session.Begin(); await storage.Outgoing.DeleteByDestination(destination); await storage.Session.Commit(); return(0); } }
private async Task <int> recoverFrom(Uri destination, SqlConnection conn) { try { Envelope[] filtered = null; List <Envelope> outgoing = null; if (_subscribers.GetOrBuild(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 (_subscribers.GetOrBuild(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 _subscribers.GetOrBuild(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); } }