fix: improve connection manager error handling + edge cases (#1450)

* increase TTL on discovery classes

* refactor dialPeer to handle edge cases

* address comment
This commit is contained in:
Danish Arora 2023-08-02 13:49:48 +05:30 committed by GitHub
parent 0b8936f1f1
commit 785df528fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 61 additions and 54 deletions

View File

@ -174,51 +174,67 @@ export class ConnectionManager
private async dialPeer(peerId: PeerId): Promise<void> { private async dialPeer(peerId: PeerId): Promise<void> {
this.currentActiveDialCount += 1; this.currentActiveDialCount += 1;
let dialAttempt = 0; let dialAttempt = 0;
while (dialAttempt <= this.options.maxDialAttemptsForPeer) { while (dialAttempt < this.options.maxDialAttemptsForPeer) {
try { try {
log(`Dialing peer ${peerId.toString()}`); log(`Dialing peer ${peerId.toString()} on attempt ${dialAttempt + 1}`);
await this.libp2p.dial(peerId); await this.libp2p.dial(peerId);
const tags = await this.getTagNamesForPeer(peerId); const tags = await this.getTagNamesForPeer(peerId);
// add tag to connection describing discovery mechanism // add tag to connection describing discovery mechanism
// don't add duplicate tags // don't add duplicate tags
this.libp2p this.libp2p.getConnections(peerId).forEach((conn) => {
.getConnections(peerId) conn.tags = Array.from(new Set([...conn.tags, ...tags]));
.forEach( });
(conn) => (conn.tags = Array.from(new Set([...conn.tags, ...tags])))
);
this.dialAttemptsForPeer.delete(peerId.toString()); this.dialAttemptsForPeer.delete(peerId.toString());
return; // Dialing succeeded, break the loop
} catch (e) { break;
const error = e as AggregateError; } catch (error) {
if (error instanceof AggregateError) {
this.dialErrorsForPeer.set(peerId.toString(), error); // Handle AggregateError
log(`Error dialing peer ${peerId.toString()} - ${error.errors}`); log(`Error dialing peer ${peerId.toString()} - ${error.errors}`);
} else {
dialAttempt = this.dialAttemptsForPeer.get(peerId.toString()) ?? 1; // Handle generic error
this.dialAttemptsForPeer.set(peerId.toString(), dialAttempt + 1);
if (dialAttempt <= this.options.maxDialAttemptsForPeer) {
log(`Reattempting dial (${dialAttempt})`);
}
}
}
try {
log( log(
`Deleting undialable peer ${peerId.toString()} from peer store. Error: ${JSON.stringify( `Error dialing peer ${peerId.toString()} - ${
this.dialErrorsForPeer.get(peerId.toString()).errors[0] (error as any).message
)}
}` }`
); );
this.dialErrorsForPeer.delete(peerId.toString()); }
return await this.libp2p.peerStore.delete(peerId); this.dialErrorsForPeer.set(peerId.toString(), error);
} catch (error) {
throw `Error deleting undialable peer ${peerId.toString()} from peer store - ${error}`; dialAttempt++;
} finally { this.dialAttemptsForPeer.set(peerId.toString(), dialAttempt);
this.currentActiveDialCount -= 1; }
}
// Always decrease the active dial count and process the dial queue
this.currentActiveDialCount--;
this.processDialQueue(); this.processDialQueue();
// If max dial attempts reached and dialing failed, delete the peer
if (dialAttempt === this.options.maxDialAttemptsForPeer) {
try {
const error = this.dialErrorsForPeer.get(peerId.toString());
let errorMessage;
if (error instanceof AggregateError) {
errorMessage = JSON.stringify(error.errors[0]);
} else {
errorMessage = error.message;
}
log(
`Deleting undialable peer ${peerId.toString()} from peer store. Error: ${errorMessage}`
);
this.dialErrorsForPeer.delete(peerId.toString());
await this.libp2p.peerStore.delete(peerId);
} catch (error) {
throw new Error(
`Error deleting undialable peer ${peerId.toString()} from peer store - ${error}`
);
}
} }
} }
@ -302,25 +318,16 @@ export class ConnectionManager
Tags.BOOTSTRAP Tags.BOOTSTRAP
); );
if (isBootstrap) {
this.dispatchEvent( this.dispatchEvent(
new CustomEvent<PeerId>( new CustomEvent<PeerId>(
EPeersByDiscoveryEvents.PEER_DISCOVERY_BOOTSTRAP, isBootstrap
? EPeersByDiscoveryEvents.PEER_DISCOVERY_BOOTSTRAP
: EPeersByDiscoveryEvents.PEER_DISCOVERY_PEER_EXCHANGE,
{ {
detail: peerId, detail: peerId,
} }
) )
); );
} else {
this.dispatchEvent(
new CustomEvent<PeerId>(
EPeersByDiscoveryEvents.PEER_DISCOVERY_PEER_EXCHANGE,
{
detail: peerId,
}
)
);
}
try { try {
await this.attemptDial(peerId); await this.attemptDial(peerId);

View File

@ -22,7 +22,7 @@ const enrTree = {
const DEFAULT_BOOTSTRAP_TAG_NAME = "bootstrap"; const DEFAULT_BOOTSTRAP_TAG_NAME = "bootstrap";
const DEFAULT_BOOTSTRAP_TAG_VALUE = 50; const DEFAULT_BOOTSTRAP_TAG_VALUE = 50;
const DEFAULT_BOOTSTRAP_TAG_TTL = 120000; const DEFAULT_BOOTSTRAP_TAG_TTL = 100_000_000;
export interface DnsDiscoveryComponents { export interface DnsDiscoveryComponents {
peerStore: PeerStore; peerStore: PeerStore;

View File

@ -47,7 +47,7 @@ export interface Options {
export const DEFAULT_PEER_EXCHANGE_TAG_NAME = Tags.PEER_EXCHANGE; export const DEFAULT_PEER_EXCHANGE_TAG_NAME = Tags.PEER_EXCHANGE;
const DEFAULT_PEER_EXCHANGE_TAG_VALUE = 50; const DEFAULT_PEER_EXCHANGE_TAG_VALUE = 50;
const DEFAULT_PEER_EXCHANGE_TAG_TTL = 120000; const DEFAULT_PEER_EXCHANGE_TAG_TTL = 100_000_000;
export class PeerExchangeDiscovery export class PeerExchangeDiscovery
extends EventEmitter<PeerDiscoveryEvents> extends EventEmitter<PeerDiscoveryEvents>