async Task HandleFailedConnectedPeerAsync(Exception e, MessageRelayConnection connection) { if (connection == null) // there was no connection available { return; } if (e == null) // explicit disconnect { Debug.Assert(connection.ConnectionState.HasFlag(ConnectedPeer.State.Disconnecting)); Debug.Assert(connection.ConnectionState.HasFlag(ConnectedPeer.State.Disposed)); } else { Debug.Assert(connection.ConnectionState.HasFlag(ConnectedPeer.State.Failed)); Debug.Assert(connection.ConnectionState.HasFlag(ConnectedPeer.State.Disposed)); } if (PeerManager.ShouldRecordError(e, !this.cancellation.Token.IsCancellationRequested, connection.ToString(), this.logger)) { // set these properties on the loaded connection instance and not only in the repository, so that we can // use the cached collection of Peer objects connection.MessageRelayRecord.LastErrorUtc = DateTime.UtcNow; await this.messageRelayRecords.UpdatePeerLastError(connection.MessageRelayRecord.Id, connection.MessageRelayRecord.LastErrorUtc); } this.connections.TryRemove(connection.MessageRelayRecord.Id, out _); }
public async Task <MessageRelayConnection> SelectNextConnectionAsync() { IReadOnlyList <MessageRelayRecord> allRecords = await this.messageRelayRecords.GetAllMessageRelayRecordsAsync(); if (allRecords.Count == 0) { this.logger.LogWarning("No relay addresses in the store - can't select a connection candidate!"); return(null); } // peers, shortest success ago first var hottestRecords = allRecords .Where(x => !IsExcluded(x)) // e.g. if we are already connected, or the last error is less than a certain time ago .OrderBy(x => DateTimeOffset.UtcNow - x.LastSeenUtc) // then, try the best candidates first .ThenByDescending(x => DateTimeOffset.UtcNow - x.LastErrorUtc) // then, try the candidates where the last error is longest ago .ToList(); if (hottestRecords.Count == 0) { this.logger.LogDebug("After applying the filtering rules, no connection candidates remain for selection."); return(null); } MessageRelayRecord messageRelayRecord = hottestRecords[0]; this.logger.LogDebug($"Selected connection candidate {messageRelayRecord}, last seen {DateTimeOffset.UtcNow - messageRelayRecord.LastSeenUtc} ago, last error {DateTimeOffset.UtcNow - messageRelayRecord.LastErrorUtc} ago."); var messageRelayConnection = new MessageRelayConnection(messageRelayRecord, this.cancellation.Token); bool addSuccess = this.connections.TryAdd(messageRelayRecord.Id, messageRelayConnection); Debug.Assert(addSuccess, $"Bug: Peer {messageRelayRecord} was already in the ConnectedPeers dictionary - that should not happen."); return(messageRelayConnection); }
async Task ConnectAndRunAsync(MessageRelayConnection createdInstance) { var connectedInstance = await CreateConnectedPeerBlockingOrThrowAsync(createdInstance); if (connectedInstance != null) { this.logger.LogInformation($"Successfully created connected peer {createdInstance}, loading off to new thread."); //await RunNetworkPeer(createdInstance); } }
async Task <MessageRelayConnection> CreateConnectedPeerBlockingOrThrowAsync(MessageRelayConnection connection) { try { connection.ConnectionState |= ConnectedPeer.State.Connecting; await connection.ConnectAsync(); connection.ConnectionState &= ~ConnectedPeer.State.Connecting; connection.ConnectionState |= ConnectedPeer.State.Connected; return(connection); } catch (Exception e) { await HandleFailedConnectedPeerAsync(e, connection); return(null); } }
public async Task <List <IEnvelope> > SendRequestAsync(byte[] request) { var response = new List <IEnvelope>(); MessageRelayConnection currentConnection = null; try { await this.semaphore.WaitAsync(); // this definitely deadlocks sometimes currentConnection = GetRandomConnection(); if (currentConnection == null) { throw new MessageRelayConnectionException("No connection(s) available, please retry later.", null) { NoConnectionAvailable = true } } ; await currentConnection.SendAsync(request); response.AddRange(await currentConnection.ReceiveAsync()); } catch (Exception e) { await HandleFailedConnectedPeerAsync(e, currentConnection); throw; } finally { this.semaphore.Release(); } return(response); }