@olane/o-node 0.7.12-alpha.67 → 0.7.12-alpha.68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/interfaces/o-node.config.d.ts +2 -16
- package/dist/src/interfaces/o-node.config.d.ts.map +1 -1
- package/dist/src/managers/o-connection-heartbeat.manager.d.ts +13 -9
- package/dist/src/managers/o-connection-heartbeat.manager.d.ts.map +1 -1
- package/dist/src/managers/o-connection-heartbeat.manager.js +47 -46
- package/dist/src/o-node.d.ts +1 -3
- package/dist/src/o-node.d.ts.map +1 -1
- package/dist/src/o-node.js +36 -21
- package/package.json +6 -6
|
@@ -4,31 +4,17 @@ export interface oNodeConfig extends oCoreConfig {
|
|
|
4
4
|
leader: oNodeAddress | null;
|
|
5
5
|
parent: oNodeAddress | null;
|
|
6
6
|
/**
|
|
7
|
-
* Connection
|
|
8
|
-
* Detects dead connections
|
|
7
|
+
* Connection health monitoring configuration
|
|
8
|
+
* Detects dead connections by checking libp2p connection state
|
|
9
9
|
*/
|
|
10
10
|
connectionHeartbeat?: {
|
|
11
11
|
enabled?: boolean;
|
|
12
12
|
intervalMs?: number;
|
|
13
|
-
timeoutMs?: number;
|
|
14
13
|
failureThreshold?: number;
|
|
15
14
|
checkChildren?: boolean;
|
|
16
15
|
checkParent?: boolean;
|
|
17
16
|
checkLeader?: boolean;
|
|
18
17
|
};
|
|
19
|
-
/**
|
|
20
|
-
* Automatic reconnection configuration
|
|
21
|
-
* Handles parent connection failures and attempts to reconnect
|
|
22
|
-
*/
|
|
23
|
-
reconnection?: {
|
|
24
|
-
enabled?: boolean;
|
|
25
|
-
maxAttempts?: number;
|
|
26
|
-
baseDelayMs?: number;
|
|
27
|
-
maxDelayMs?: number;
|
|
28
|
-
useLeaderFallback?: boolean;
|
|
29
|
-
parentDiscoveryIntervalMs?: number;
|
|
30
|
-
parentDiscoveryMaxDelayMs?: number;
|
|
31
|
-
};
|
|
32
18
|
/**
|
|
33
19
|
* Connection timeout configuration
|
|
34
20
|
* Controls timeouts for stream read and drain operations in connections
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-node.config.d.ts","sourceRoot":"","sources":["../../../src/interfaces/o-node.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC9C,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAE5B;;;OAGG;IACH,mBAAmB,CAAC,EAAE;QACpB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,
|
|
1
|
+
{"version":3,"file":"o-node.config.d.ts","sourceRoot":"","sources":["../../../src/interfaces/o-node.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC9C,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAE5B;;;OAGG;IACH,mBAAmB,CAAC,EAAE;QACpB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,WAAW,CAAC,EAAE,OAAO,CAAC;KACvB,CAAC;IAEF;;;OAGG;IACH,kBAAkB,CAAC,EAAE;QACnB;;;WAGG;QACH,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB;;;WAGG;QACH,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IAEF,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC"}
|
|
@@ -4,7 +4,6 @@ import { IHeartbeatableNode } from '../interfaces/i-heartbeatable-node.js';
|
|
|
4
4
|
export interface HeartbeatConfig {
|
|
5
5
|
enabled: boolean;
|
|
6
6
|
intervalMs: number;
|
|
7
|
-
timeoutMs: number;
|
|
8
7
|
failureThreshold: number;
|
|
9
8
|
checkChildren: boolean;
|
|
10
9
|
checkParent: boolean;
|
|
@@ -19,14 +18,15 @@ export interface ConnectionHealth {
|
|
|
19
18
|
status: 'healthy' | 'degraded' | 'dead';
|
|
20
19
|
}
|
|
21
20
|
/**
|
|
22
|
-
* Connection
|
|
21
|
+
* Connection Health Monitor
|
|
23
22
|
*
|
|
24
|
-
*
|
|
25
|
-
* Continuously
|
|
23
|
+
* Monitors connection health by checking libp2p's connection state directly.
|
|
24
|
+
* Continuously checks parent and children connections to detect failures early.
|
|
26
25
|
*
|
|
27
26
|
* How it works:
|
|
28
|
-
* - Every `intervalMs`,
|
|
29
|
-
* -
|
|
27
|
+
* - Every `intervalMs`, checks connection status of all tracked connections
|
|
28
|
+
* - Uses libp2p's connection state (no network overhead from pings)
|
|
29
|
+
* - If connection is not open, increments failure counter
|
|
30
30
|
* - After `failureThreshold` failures, marks connection as dead
|
|
31
31
|
* - Emits events for degraded/recovered/dead connections
|
|
32
32
|
* - Automatically removes dead children from hierarchy
|
|
@@ -41,9 +41,13 @@ export declare class oConnectionHeartbeatManager extends oObject {
|
|
|
41
41
|
constructor(node: IHeartbeatableNode, config: HeartbeatConfig);
|
|
42
42
|
start(): Promise<void>;
|
|
43
43
|
stop(): Promise<void>;
|
|
44
|
-
private
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
private performHealthCheckCycle;
|
|
45
|
+
/**
|
|
46
|
+
* Check if a connection to the given address is open by examining libp2p's connection state
|
|
47
|
+
* @returns true if an open connection exists, false otherwise
|
|
48
|
+
*/
|
|
49
|
+
private checkConnectionStatus;
|
|
50
|
+
private checkTarget;
|
|
47
51
|
private handleConnectionDead;
|
|
48
52
|
private emitConnectionDegradedEvent;
|
|
49
53
|
private emitConnectionRecoveredEvent;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-connection-heartbeat.manager.d.ts","sourceRoot":"","sources":["../../../src/managers/o-connection-heartbeat.manager.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EAOR,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAE3E,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,
|
|
1
|
+
{"version":3,"file":"o-connection-heartbeat.manager.d.ts","sourceRoot":"","sources":["../../../src/managers/o-connection-heartbeat.manager.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EAOR,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAE3E,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,YAAY,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;CACzC;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,2BAA4B,SAAQ,OAAO;IAMpD,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,MAAM;IANhB,OAAO,CAAC,iBAAiB,CAAC,CAAiB;IAC3C,OAAO,CAAC,SAAS,CAAuC;IACxD,OAAO,CAAC,SAAS,CAAS;gBAGhB,IAAI,EAAE,kBAAkB,EACxB,MAAM,EAAE,eAAe;IAK3B,KAAK;IAqBL,IAAI;YAQI,uBAAuB;IAgDrC;;;OAGG;IACH,OAAO,CAAC,qBAAqB;YA8Bf,WAAW;IAoEzB,OAAO,CAAC,oBAAoB;IAyD5B,OAAO,CAAC,2BAA2B;IAmBnC,OAAO,CAAC,4BAA4B;IAiBpC;;OAEG;IACH,eAAe,IAAI,gBAAgB,EAAE;IAIrC;;OAEG;IACH,mBAAmB,CAAC,OAAO,EAAE,YAAY,GAAG,gBAAgB,GAAG,SAAS;IAIxE;;OAEG;IACH,SAAS,IAAI,eAAe;CAG7B"}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { oObject, ChildLeftEvent, ParentDisconnectedEvent, LeaderDisconnectedEvent, ConnectionDegradedEvent, ConnectionRecoveredEvent, oAddress, } from '@olane/o-core';
|
|
2
2
|
/**
|
|
3
|
-
* Connection
|
|
3
|
+
* Connection Health Monitor
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* Continuously
|
|
5
|
+
* Monitors connection health by checking libp2p's connection state directly.
|
|
6
|
+
* Continuously checks parent and children connections to detect failures early.
|
|
7
7
|
*
|
|
8
8
|
* How it works:
|
|
9
|
-
* - Every `intervalMs`,
|
|
10
|
-
* -
|
|
9
|
+
* - Every `intervalMs`, checks connection status of all tracked connections
|
|
10
|
+
* - Uses libp2p's connection state (no network overhead from pings)
|
|
11
|
+
* - If connection is not open, increments failure counter
|
|
11
12
|
* - After `failureThreshold` failures, marks connection as dead
|
|
12
13
|
* - Emits events for degraded/recovered/dead connections
|
|
13
14
|
* - Automatically removes dead children from hierarchy
|
|
@@ -23,15 +24,15 @@ export class oConnectionHeartbeatManager extends oObject {
|
|
|
23
24
|
}
|
|
24
25
|
async start() {
|
|
25
26
|
if (!this.config.enabled) {
|
|
26
|
-
this.logger.debug('Connection
|
|
27
|
+
this.logger.debug('Connection health monitoring disabled');
|
|
27
28
|
return;
|
|
28
29
|
}
|
|
29
|
-
this.logger.info(`Starting connection
|
|
30
|
-
`
|
|
30
|
+
this.logger.info(`Starting connection health monitoring: interval=${this.config.intervalMs}ms, ` +
|
|
31
|
+
`threshold=${this.config.failureThreshold}`);
|
|
31
32
|
// Immediate first check
|
|
32
|
-
await this.
|
|
33
|
+
await this.performHealthCheckCycle();
|
|
33
34
|
// Schedule recurring checks
|
|
34
|
-
this.heartbeatInterval = setInterval(() => this.
|
|
35
|
+
this.heartbeatInterval = setInterval(() => this.performHealthCheckCycle(), this.config.intervalMs);
|
|
35
36
|
}
|
|
36
37
|
async stop() {
|
|
37
38
|
if (this.heartbeatInterval) {
|
|
@@ -40,8 +41,8 @@ export class oConnectionHeartbeatManager extends oObject {
|
|
|
40
41
|
}
|
|
41
42
|
this.healthMap.clear();
|
|
42
43
|
}
|
|
43
|
-
async
|
|
44
|
-
if (
|
|
44
|
+
async performHealthCheckCycle() {
|
|
45
|
+
if (this.isRunning) {
|
|
45
46
|
return;
|
|
46
47
|
}
|
|
47
48
|
this.isRunning = true;
|
|
@@ -60,7 +61,7 @@ export class oConnectionHeartbeatManager extends oObject {
|
|
|
60
61
|
// Use this.node.parent getter to get the current parent address with transports
|
|
61
62
|
// rather than getParents() which may have a stale reference
|
|
62
63
|
const parent = this.node.parent;
|
|
63
|
-
// make sure that we don't double
|
|
64
|
+
// make sure that we don't double check the leader
|
|
64
65
|
if (parent && parent?.toString() !== oAddress.leader().toString()) {
|
|
65
66
|
targets.push({ address: parent, role: 'parent' });
|
|
66
67
|
}
|
|
@@ -72,26 +73,38 @@ export class oConnectionHeartbeatManager extends oObject {
|
|
|
72
73
|
targets.push({ address: child, role: 'child' });
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
|
-
//
|
|
76
|
-
await Promise.allSettled(targets.map((target) => this.
|
|
76
|
+
// Check all targets in parallel
|
|
77
|
+
await Promise.allSettled(targets.map((target) => this.checkTarget(target.address, target.role)));
|
|
77
78
|
this.isRunning = false;
|
|
78
79
|
}
|
|
79
|
-
|
|
80
|
+
/**
|
|
81
|
+
* Check if a connection to the given address is open by examining libp2p's connection state
|
|
82
|
+
* @returns true if an open connection exists, false otherwise
|
|
83
|
+
*/
|
|
84
|
+
checkConnectionStatus(address) {
|
|
80
85
|
if (address.toString() === this.node.address.toString()) {
|
|
81
|
-
return
|
|
86
|
+
return true; // Self-connection is always "open"
|
|
82
87
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
88
|
+
if (!address.libp2pTransports.length) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
// Get peer ID from the address
|
|
93
|
+
const peerIdString = address.libp2pTransports[0].toPeerId();
|
|
94
|
+
// Get all connections to this peer from libp2p
|
|
95
|
+
// Note: Using 'as any' since converting to proper PeerId breaks browser implementation
|
|
96
|
+
const connections = this.node.p2pNode.getConnections(peerIdString);
|
|
97
|
+
// Check if any connection is open
|
|
98
|
+
return connections.some((conn) => conn.status === 'open');
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
this.logger.debug(`Error checking connection status for ${address}`, error);
|
|
102
|
+
return false;
|
|
89
103
|
}
|
|
90
|
-
return this.node.p2pNode.services.ping.ping(transport);
|
|
91
104
|
}
|
|
92
|
-
async
|
|
105
|
+
async checkTarget(address, role) {
|
|
93
106
|
if (!address.libp2pTransports.length) {
|
|
94
|
-
this.logger.debug(`${role} has no transports, skipping
|
|
107
|
+
this.logger.debug(`${role} has no transports, skipping health check`, address);
|
|
95
108
|
return;
|
|
96
109
|
}
|
|
97
110
|
const key = address.toString();
|
|
@@ -107,36 +120,24 @@ export class oConnectionHeartbeatManager extends oObject {
|
|
|
107
120
|
};
|
|
108
121
|
this.healthMap.set(key, health);
|
|
109
122
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
//
|
|
114
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
115
|
-
setTimeout(() => reject(new Error('Ping timeout')), this.config.timeoutMs);
|
|
116
|
-
});
|
|
117
|
-
// Race between ping and timeout
|
|
118
|
-
// The ping service accepts PeerId as string or object
|
|
119
|
-
await Promise.race([this.doPing(address), timeoutPromise]);
|
|
120
|
-
const latency = Date.now() - startTime;
|
|
121
|
-
// Success - update health
|
|
123
|
+
// Check connection status using libp2p's connection state
|
|
124
|
+
const isOpen = this.checkConnectionStatus(address);
|
|
125
|
+
if (isOpen) {
|
|
126
|
+
// Connection is open - success
|
|
122
127
|
health.lastSuccessfulPing = Date.now();
|
|
123
128
|
health.consecutiveFailures = 0;
|
|
124
|
-
health.averageLatency =
|
|
125
|
-
health.averageLatency === 0
|
|
126
|
-
? latency
|
|
127
|
-
: health.averageLatency * 0.7 + latency * 0.3; // Exponential moving average
|
|
128
129
|
const previousStatus = health.status;
|
|
129
130
|
health.status = 'healthy';
|
|
130
131
|
// Emit recovery event if was degraded
|
|
131
132
|
if (previousStatus === 'degraded') {
|
|
132
|
-
this.logger.info(`Connection recovered: ${address}
|
|
133
|
+
this.logger.info(`Connection recovered: ${address}`);
|
|
133
134
|
this.emitConnectionRecoveredEvent(address, role);
|
|
134
135
|
}
|
|
135
|
-
// this.logger.debug(`Ping successful: ${address} (${latency}ms)`);
|
|
136
136
|
}
|
|
137
|
-
|
|
137
|
+
else {
|
|
138
|
+
// Connection is not open
|
|
138
139
|
health.consecutiveFailures++;
|
|
139
|
-
this.logger.warn(`
|
|
140
|
+
this.logger.warn(`Connection check failed: ${address} (failures: ${health.consecutiveFailures}/${this.config.failureThreshold})`);
|
|
140
141
|
// Update status based on failure count
|
|
141
142
|
if (health.consecutiveFailures >= this.config.failureThreshold) {
|
|
142
143
|
this.handleConnectionDead(address, role, health);
|
package/dist/src/o-node.d.ts
CHANGED
|
@@ -9,7 +9,6 @@ import { oNodeConnection } from './connection/o-node-connection.js';
|
|
|
9
9
|
import { oNodeConnectionManager } from './connection/o-node-connection.manager.js';
|
|
10
10
|
import { oToolBase } from '@olane/o-tool';
|
|
11
11
|
import { oConnectionHeartbeatManager } from './managers/o-connection-heartbeat.manager.js';
|
|
12
|
-
import { oReconnectionManager } from './managers/o-reconnection.manager.js';
|
|
13
12
|
import { oNodeConnectionConfig } from './connection/index.js';
|
|
14
13
|
export declare class oNode extends oToolBase {
|
|
15
14
|
peerId: PeerId;
|
|
@@ -19,7 +18,6 @@ export declare class oNode extends oToolBase {
|
|
|
19
18
|
connectionManager: oNodeConnectionManager;
|
|
20
19
|
hierarchyManager: oNodeHierarchyManager;
|
|
21
20
|
connectionHeartbeatManager?: oConnectionHeartbeatManager;
|
|
22
|
-
reconnectionManager?: oReconnectionManager;
|
|
23
21
|
protected didRegister: boolean;
|
|
24
22
|
constructor(config: oNodeConfig);
|
|
25
23
|
get leader(): oNodeAddress | null;
|
|
@@ -32,6 +30,7 @@ export declare class oNode extends oToolBase {
|
|
|
32
30
|
get parentTransports(): oNodeTransport[];
|
|
33
31
|
get transports(): oNodeTransport[];
|
|
34
32
|
unregister(): Promise<void>;
|
|
33
|
+
setKeepAliveTag(address: oNodeAddress): Promise<void>;
|
|
35
34
|
registerParent(): Promise<void>;
|
|
36
35
|
registerLeader(): Promise<void>;
|
|
37
36
|
register(): Promise<void>;
|
|
@@ -46,7 +45,6 @@ export declare class oNode extends oToolBase {
|
|
|
46
45
|
protected createNode(): Promise<Libp2p>;
|
|
47
46
|
connect(config: oNodeConnectionConfig): Promise<oNodeConnection>;
|
|
48
47
|
initConnectionManager(): Promise<void>;
|
|
49
|
-
initReconnectionManager(): Promise<void>;
|
|
50
48
|
hookInitializeFinished(): Promise<void>;
|
|
51
49
|
hookStartFinished(): Promise<void>;
|
|
52
50
|
initialize(): Promise<void>;
|
package/dist/src/o-node.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-node.d.ts","sourceRoot":"","sources":["../../src/o-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,MAAM,EACN,YAAY,
|
|
1
|
+
{"version":3,"file":"o-node.d.ts","sourceRoot":"","sources":["../../src/o-node.ts"],"names":[],"mappings":"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"}
|
package/dist/src/o-node.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createNode, defaultLibp2pConfig, } from '@olane/o-config';
|
|
1
|
+
import { createNode, defaultLibp2pConfig, KEEP_ALIVE, } from '@olane/o-config';
|
|
2
2
|
import { v4 as uuidv4 } from 'uuid';
|
|
3
3
|
import { oNodeRouter } from './router/o-node.router.js';
|
|
4
4
|
import { oNodeHierarchyManager } from './o-node.hierarchy-manager.js';
|
|
@@ -11,7 +11,6 @@ import { oMethodResolver, oToolBase } from '@olane/o-tool';
|
|
|
11
11
|
import { oLeaderResolverFallback } from './router/index.js';
|
|
12
12
|
import { oNodeNotificationManager } from './o-node.notification-manager.js';
|
|
13
13
|
import { oConnectionHeartbeatManager } from './managers/o-connection-heartbeat.manager.js';
|
|
14
|
-
import { oReconnectionManager } from './managers/o-reconnection.manager.js';
|
|
15
14
|
export class oNode extends oToolBase {
|
|
16
15
|
constructor(config) {
|
|
17
16
|
super(config);
|
|
@@ -106,6 +105,30 @@ export class oNode extends oToolBase {
|
|
|
106
105
|
this.logger.error('Failed to unregister from network:', error);
|
|
107
106
|
});
|
|
108
107
|
}
|
|
108
|
+
async setKeepAliveTag(address) {
|
|
109
|
+
if (!address || !address.libp2pTransports?.length) {
|
|
110
|
+
this.logger.warn('Address has no transports, skipping keep alive tag!', address);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
const peers = await this.p2pNode.peerStore.all();
|
|
115
|
+
// find the peer that is already indexed rather than building the PeerId from the string value to avoid browser issues
|
|
116
|
+
const peer = peers.find((p) => p.id.toString() === address.libp2pTransports[0].toPeerId().toString());
|
|
117
|
+
if (!peer) {
|
|
118
|
+
this.logger.warn('Peer not found, skipping keep alive tag!', address);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
await this.p2pNode.peerStore.merge(peer.id, {
|
|
122
|
+
tags: {
|
|
123
|
+
[KEEP_ALIVE]: { value: 100 },
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
this.logger.debug('Set keep alive tag for peer:', peer.id.toString(), ' with address:', address.toString());
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
this.logger.error('Failed to set keep alive tag:', error);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
109
132
|
async registerParent() {
|
|
110
133
|
if (this.type === NodeType.LEADER) {
|
|
111
134
|
this.logger.debug('Skipping parent registration, node is leader');
|
|
@@ -118,7 +141,7 @@ export class oNode extends oToolBase {
|
|
|
118
141
|
}
|
|
119
142
|
else {
|
|
120
143
|
this.logger.debug('Waiting for parent and reconnecting...');
|
|
121
|
-
await this.reconnectionManager?.waitForParentAndReconnect();
|
|
144
|
+
// await this.reconnectionManager?.waitForParentAndReconnect();
|
|
122
145
|
}
|
|
123
146
|
}
|
|
124
147
|
// if no parent transports, register with the parent to get them
|
|
@@ -134,6 +157,7 @@ export class oNode extends oToolBase {
|
|
|
134
157
|
_token: this.config.joinToken,
|
|
135
158
|
},
|
|
136
159
|
});
|
|
160
|
+
this.setKeepAliveTag(this.parent);
|
|
137
161
|
}
|
|
138
162
|
}
|
|
139
163
|
async registerLeader() {
|
|
@@ -149,6 +173,7 @@ export class oNode extends oToolBase {
|
|
|
149
173
|
},
|
|
150
174
|
};
|
|
151
175
|
await this.use(address, params);
|
|
176
|
+
this.setKeepAliveTag(this.leader);
|
|
152
177
|
}
|
|
153
178
|
async register() {
|
|
154
179
|
if (this.type === NodeType.LEADER) {
|
|
@@ -271,6 +296,13 @@ export class oNode extends oToolBase {
|
|
|
271
296
|
...(this.config.network?.connectionGater || {}),
|
|
272
297
|
};
|
|
273
298
|
}
|
|
299
|
+
params.connectionManager = {
|
|
300
|
+
...(params.connectionManager || {}),
|
|
301
|
+
reconnectRetries: 20,
|
|
302
|
+
reconnectRetryInterval: 2000,
|
|
303
|
+
reconnectBackoffFactor: 1.2,
|
|
304
|
+
maxParallelReconnects: 10,
|
|
305
|
+
};
|
|
274
306
|
// handle the address encapsulation
|
|
275
307
|
if (this.config.leader &&
|
|
276
308
|
!this.address.protocol.includes(this.config.leader.protocol)) {
|
|
@@ -311,27 +343,12 @@ export class oNode extends oToolBase {
|
|
|
311
343
|
runOnLimitedConnection: this.config.runOnLimitedConnection ?? false,
|
|
312
344
|
});
|
|
313
345
|
}
|
|
314
|
-
async initReconnectionManager() {
|
|
315
|
-
// Initialize reconnection manager
|
|
316
|
-
if (this.config.reconnection?.enabled !== false) {
|
|
317
|
-
this.reconnectionManager = new oReconnectionManager(this, {
|
|
318
|
-
enabled: true,
|
|
319
|
-
maxAttempts: this.config.reconnection?.maxAttempts ?? 10,
|
|
320
|
-
baseDelayMs: this.config.reconnection?.baseDelayMs ?? 5000,
|
|
321
|
-
maxDelayMs: this.config.reconnection?.maxDelayMs ?? 60000,
|
|
322
|
-
useLeaderFallback: this.config.reconnection?.useLeaderFallback ?? true,
|
|
323
|
-
parentDiscoveryIntervalMs: this.config.reconnection?.parentDiscoveryIntervalMs ?? 10000,
|
|
324
|
-
parentDiscoveryMaxDelayMs: this.config.reconnection?.parentDiscoveryMaxDelayMs ?? 60000,
|
|
325
|
-
});
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
346
|
async hookInitializeFinished() { }
|
|
329
347
|
async hookStartFinished() {
|
|
330
|
-
// Initialize connection
|
|
348
|
+
// Initialize connection health monitor
|
|
331
349
|
this.connectionHeartbeatManager = new oConnectionHeartbeatManager(this, {
|
|
332
350
|
enabled: this.config.connectionHeartbeat?.enabled ?? true,
|
|
333
351
|
intervalMs: this.config.connectionHeartbeat?.intervalMs ?? 15000,
|
|
334
|
-
timeoutMs: this.config.connectionHeartbeat?.timeoutMs ?? 15000,
|
|
335
352
|
failureThreshold: this.config.connectionHeartbeat?.failureThreshold ?? 3,
|
|
336
353
|
checkChildren: this.config.connectionHeartbeat?.checkChildren ?? false,
|
|
337
354
|
checkParent: this.config.connectionHeartbeat?.checkParent ?? true,
|
|
@@ -365,8 +382,6 @@ export class oNode extends oToolBase {
|
|
|
365
382
|
this.logger.debug('Adding leader resolver fallback...');
|
|
366
383
|
this.router.addResolver(new oLeaderResolverFallback(this.address));
|
|
367
384
|
}
|
|
368
|
-
// initialize reconnection manager
|
|
369
|
-
await this.initReconnectionManager();
|
|
370
385
|
await this.hookInitializeFinished();
|
|
371
386
|
}
|
|
372
387
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olane/o-node",
|
|
3
|
-
"version": "0.7.12-alpha.
|
|
3
|
+
"version": "0.7.12-alpha.68",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"types": "dist/src/index.d.ts",
|
|
@@ -54,12 +54,12 @@
|
|
|
54
54
|
"typescript": "5.4.5"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@olane/o-config": "0.7.12-alpha.
|
|
58
|
-
"@olane/o-core": "0.7.12-alpha.
|
|
59
|
-
"@olane/o-protocol": "0.7.12-alpha.
|
|
60
|
-
"@olane/o-tool": "0.7.12-alpha.
|
|
57
|
+
"@olane/o-config": "0.7.12-alpha.68",
|
|
58
|
+
"@olane/o-core": "0.7.12-alpha.68",
|
|
59
|
+
"@olane/o-protocol": "0.7.12-alpha.68",
|
|
60
|
+
"@olane/o-tool": "0.7.12-alpha.68",
|
|
61
61
|
"debug": "^4.4.1",
|
|
62
62
|
"dotenv": "^16.5.0"
|
|
63
63
|
},
|
|
64
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "3ffe39de1430bed3673c13adc1b144f9016967dc"
|
|
65
65
|
}
|