@celerispay/hazelcast-client 3.12.5-1 → 3.12.5-3
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/lib/invocation/ClientConnection.d.ts +14 -0
- package/lib/invocation/ClientConnection.js +65 -1
- package/lib/invocation/ClientConnectionManager.d.ts +31 -0
- package/lib/invocation/ClientConnectionManager.js +80 -2
- package/lib/invocation/ClusterService.d.ts +8 -0
- package/lib/invocation/ClusterService.js +103 -11
- package/package.json +1 -1
|
@@ -46,7 +46,12 @@ export declare class ClientConnection {
|
|
|
46
46
|
private readonly socket;
|
|
47
47
|
private readonly writer;
|
|
48
48
|
private readonly reader;
|
|
49
|
+
private readonly logger;
|
|
49
50
|
constructor(client: HazelcastClient, address: Address, socket: net.Socket);
|
|
51
|
+
/**
|
|
52
|
+
* Sets up socket event handlers for proper connection state tracking
|
|
53
|
+
*/
|
|
54
|
+
private setupSocketEventHandlers();
|
|
50
55
|
/**
|
|
51
56
|
* Returns the address of local port that is associated with this connection.
|
|
52
57
|
* @returns
|
|
@@ -65,7 +70,16 @@ export declare class ClientConnection {
|
|
|
65
70
|
* Closes this connection.
|
|
66
71
|
*/
|
|
67
72
|
close(): void;
|
|
73
|
+
/**
|
|
74
|
+
* Checks if the connection is alive and healthy
|
|
75
|
+
* @returns true if connection is alive, false otherwise
|
|
76
|
+
*/
|
|
68
77
|
isAlive(): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Performs a more thorough health check of the connection
|
|
80
|
+
* @returns true if connection is healthy, false otherwise
|
|
81
|
+
*/
|
|
82
|
+
isHealthy(): boolean;
|
|
69
83
|
isHeartbeating(): boolean;
|
|
70
84
|
setHeartbeating(heartbeating: boolean): void;
|
|
71
85
|
isAuthenticatedAsOwner(): boolean;
|
|
@@ -217,7 +217,36 @@ var ClientConnection = /** @class */ (function () {
|
|
|
217
217
|
_this.lastWriteTimeMillis = Date.now();
|
|
218
218
|
});
|
|
219
219
|
this.reader = new FrameReader();
|
|
220
|
+
this.logger = client.getLoggingService().getLogger();
|
|
221
|
+
// Add socket event handlers for proper connection state tracking
|
|
222
|
+
this.setupSocketEventHandlers();
|
|
220
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* Sets up socket event handlers for proper connection state tracking
|
|
226
|
+
*/
|
|
227
|
+
ClientConnection.prototype.setupSocketEventHandlers = function () {
|
|
228
|
+
var _this = this;
|
|
229
|
+
// Handle socket close events
|
|
230
|
+
this.socket.on('close', function () {
|
|
231
|
+
_this.closedTime = Date.now();
|
|
232
|
+
_this.logger.debug('ClientConnection', "Socket closed for " + _this.address.toString());
|
|
233
|
+
});
|
|
234
|
+
// Handle socket end events
|
|
235
|
+
this.socket.on('end', function () {
|
|
236
|
+
_this.closedTime = Date.now();
|
|
237
|
+
_this.logger.debug('ClientConnection', "Socket ended by remote for " + _this.address.toString());
|
|
238
|
+
});
|
|
239
|
+
// Handle socket errors
|
|
240
|
+
this.socket.on('error', function (error) {
|
|
241
|
+
_this.logger.warn('ClientConnection', "Socket error for " + _this.address.toString() + ":", error);
|
|
242
|
+
// Don't set closedTime here as the socket might still be usable
|
|
243
|
+
});
|
|
244
|
+
// Handle socket timeout
|
|
245
|
+
this.socket.on('timeout', function () {
|
|
246
|
+
_this.logger.warn('ClientConnection', "Socket timeout for " + _this.address.toString());
|
|
247
|
+
// Don't set closedTime here as the socket might still be usable
|
|
248
|
+
});
|
|
249
|
+
};
|
|
221
250
|
/**
|
|
222
251
|
* Returns the address of local port that is associated with this connection.
|
|
223
252
|
* @returns
|
|
@@ -254,8 +283,43 @@ var ClientConnection = /** @class */ (function () {
|
|
|
254
283
|
this.socket.end();
|
|
255
284
|
this.closedTime = Date.now();
|
|
256
285
|
};
|
|
286
|
+
/**
|
|
287
|
+
* Checks if the connection is alive and healthy
|
|
288
|
+
* @returns true if connection is alive, false otherwise
|
|
289
|
+
*/
|
|
257
290
|
ClientConnection.prototype.isAlive = function () {
|
|
258
|
-
|
|
291
|
+
// Check if we've explicitly closed the connection
|
|
292
|
+
if (this.closedTime !== 0) {
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
// Check if the underlying socket is still connected
|
|
296
|
+
if (!this.socket || this.socket.destroyed) {
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
// Check if the socket is writable (indicates it's still connected)
|
|
300
|
+
if (!this.socket.writable) {
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
// Check if we've received data recently (within last 30 seconds)
|
|
304
|
+
var now = Date.now();
|
|
305
|
+
var lastReadThreshold = 30000; // 30 seconds
|
|
306
|
+
if (this.lastReadTimeMillis > 0 && (now - this.lastReadTimeMillis) > lastReadThreshold) {
|
|
307
|
+
// If we haven't received data for a while, the connection might be stale
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
return true;
|
|
311
|
+
};
|
|
312
|
+
/**
|
|
313
|
+
* Performs a more thorough health check of the connection
|
|
314
|
+
* @returns true if connection is healthy, false otherwise
|
|
315
|
+
*/
|
|
316
|
+
ClientConnection.prototype.isHealthy = function () {
|
|
317
|
+
if (!this.isAlive()) {
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
// Additional health checks can be added here
|
|
321
|
+
// For now, just check if we're still heartbeating
|
|
322
|
+
return this.isHeartbeating();
|
|
259
323
|
};
|
|
260
324
|
ClientConnection.prototype.isHeartbeating = function () {
|
|
261
325
|
return this.heartbeating;
|
|
@@ -36,6 +36,37 @@ export declare class ClientConnectionManager extends EventEmitter {
|
|
|
36
36
|
getActiveConnections(): {
|
|
37
37
|
[address: string]: ClientConnection;
|
|
38
38
|
};
|
|
39
|
+
/**
|
|
40
|
+
* Checks if we already have a connection to the given address
|
|
41
|
+
* @param address The address to check
|
|
42
|
+
* @returns true if connection exists and is healthy, false otherwise
|
|
43
|
+
*/
|
|
44
|
+
hasConnection(address: Address): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Forces cleanup of all dead connections
|
|
47
|
+
* This is useful during failover to prevent connection leakage
|
|
48
|
+
*/
|
|
49
|
+
forceCleanupDeadConnections(): void;
|
|
50
|
+
/**
|
|
51
|
+
* Gets an existing connection to a specific address if it exists
|
|
52
|
+
* @param address The address to check for existing connection
|
|
53
|
+
* @returns The existing connection or undefined if none exists
|
|
54
|
+
*/
|
|
55
|
+
getConnection(address: Address): ClientConnection | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* Gets all established connections
|
|
58
|
+
* @returns Object containing all established connections
|
|
59
|
+
*/
|
|
60
|
+
getEstablishedConnections(): {
|
|
61
|
+
[address: string]: ClientConnection;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Gets all pending connections
|
|
65
|
+
* @returns Object containing all pending connections
|
|
66
|
+
*/
|
|
67
|
+
getPendingConnections(): {
|
|
68
|
+
[address: string]: Promise.Resolver<ClientConnection>;
|
|
69
|
+
};
|
|
39
70
|
/**
|
|
40
71
|
* Returns the {@link ClientConnection} with given {@link Address}. If there is no such connection established,
|
|
41
72
|
* it first connects to the address and then return the {@link ClientConnection}.
|
|
@@ -98,6 +98,17 @@ var ClientConnectionManager = /** @class */ (function (_super) {
|
|
|
98
98
|
_this.destroyConnection(connection.getAddress());
|
|
99
99
|
}
|
|
100
100
|
});
|
|
101
|
+
// Log current connection state
|
|
102
|
+
var activeConnections = Object.keys(this.establishedConnections).length;
|
|
103
|
+
var pendingConnections = Object.keys(this.pendingConnections).length;
|
|
104
|
+
var failedConnections = this.failedConnections.size;
|
|
105
|
+
this.logger.debug('ClientConnectionManager', "Connection State - Active: " + activeConnections + ", Pending: " + pendingConnections + ", Failed: " + failedConnections);
|
|
106
|
+
if (activeConnections > 0) {
|
|
107
|
+
Object.keys(this.establishedConnections).forEach(function (addressStr) {
|
|
108
|
+
var connection = _this.establishedConnections[addressStr];
|
|
109
|
+
_this.logger.debug('ClientConnectionManager', "Connection to " + addressStr + ": Alive=" + connection.isAlive() + ", Owner=" + connection.isAuthenticatedAsOwner());
|
|
110
|
+
});
|
|
111
|
+
}
|
|
101
112
|
};
|
|
102
113
|
ClientConnectionManager.prototype.checkConnectionHealth = function () {
|
|
103
114
|
// Use Object.keys() instead of Object.values() for compatibility
|
|
@@ -112,8 +123,8 @@ var ClientConnectionManager = /** @class */ (function (_super) {
|
|
|
112
123
|
}
|
|
113
124
|
};
|
|
114
125
|
ClientConnectionManager.prototype.isConnectionHealthy = function (connection) {
|
|
115
|
-
//
|
|
116
|
-
return connection.
|
|
126
|
+
// Use the improved health check method
|
|
127
|
+
return connection.isHealthy();
|
|
117
128
|
};
|
|
118
129
|
ClientConnectionManager.prototype.retryConnection = function (address, asOwner, retryCount) {
|
|
119
130
|
var _this = this;
|
|
@@ -160,6 +171,73 @@ var ClientConnectionManager = /** @class */ (function (_super) {
|
|
|
160
171
|
ClientConnectionManager.prototype.getActiveConnections = function () {
|
|
161
172
|
return this.establishedConnections;
|
|
162
173
|
};
|
|
174
|
+
/**
|
|
175
|
+
* Checks if we already have a connection to the given address
|
|
176
|
+
* @param address The address to check
|
|
177
|
+
* @returns true if connection exists and is healthy, false otherwise
|
|
178
|
+
*/
|
|
179
|
+
ClientConnectionManager.prototype.hasConnection = function (address) {
|
|
180
|
+
var addressStr = address.toString();
|
|
181
|
+
var connection = this.establishedConnections[addressStr];
|
|
182
|
+
return connection && connection.isAlive();
|
|
183
|
+
};
|
|
184
|
+
/**
|
|
185
|
+
* Forces cleanup of all dead connections
|
|
186
|
+
* This is useful during failover to prevent connection leakage
|
|
187
|
+
*/
|
|
188
|
+
ClientConnectionManager.prototype.forceCleanupDeadConnections = function () {
|
|
189
|
+
var _this = this;
|
|
190
|
+
this.logger.info('ClientConnectionManager', 'Forcing cleanup of all dead connections');
|
|
191
|
+
var addressesToRemove = [];
|
|
192
|
+
// Check all established connections
|
|
193
|
+
Object.keys(this.establishedConnections).forEach(function (addressStr) {
|
|
194
|
+
var connection = _this.establishedConnections[addressStr];
|
|
195
|
+
if (connection && !connection.isHealthy()) {
|
|
196
|
+
_this.logger.warn('ClientConnectionManager', "Found dead connection to " + addressStr + ", marking for cleanup");
|
|
197
|
+
addressesToRemove.push(addressStr);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
// Remove dead connections
|
|
201
|
+
addressesToRemove.forEach(function (addressStr) {
|
|
202
|
+
var connection = _this.establishedConnections[addressStr];
|
|
203
|
+
if (connection) {
|
|
204
|
+
_this.destroyConnection(connection.getAddress());
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
// Also clean up any pending connections that might be stuck
|
|
208
|
+
Object.keys(this.pendingConnections).forEach(function (addressStr) {
|
|
209
|
+
var pendingConnection = _this.pendingConnections[addressStr];
|
|
210
|
+
if (pendingConnection) {
|
|
211
|
+
_this.logger.warn('ClientConnectionManager', "Cleaning up stuck pending connection to " + addressStr);
|
|
212
|
+
pendingConnection.reject(new Error('Connection cleanup forced'));
|
|
213
|
+
delete _this.pendingConnections[addressStr];
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
this.logger.info('ClientConnectionManager', "Cleanup completed. Removed " + addressesToRemove.length + " dead connections");
|
|
217
|
+
};
|
|
218
|
+
/**
|
|
219
|
+
* Gets an existing connection to a specific address if it exists
|
|
220
|
+
* @param address The address to check for existing connection
|
|
221
|
+
* @returns The existing connection or undefined if none exists
|
|
222
|
+
*/
|
|
223
|
+
ClientConnectionManager.prototype.getConnection = function (address) {
|
|
224
|
+
var addressStr = address.toString();
|
|
225
|
+
return this.establishedConnections[addressStr];
|
|
226
|
+
};
|
|
227
|
+
/**
|
|
228
|
+
* Gets all established connections
|
|
229
|
+
* @returns Object containing all established connections
|
|
230
|
+
*/
|
|
231
|
+
ClientConnectionManager.prototype.getEstablishedConnections = function () {
|
|
232
|
+
return this.establishedConnections;
|
|
233
|
+
};
|
|
234
|
+
/**
|
|
235
|
+
* Gets all pending connections
|
|
236
|
+
* @returns Object containing all pending connections
|
|
237
|
+
*/
|
|
238
|
+
ClientConnectionManager.prototype.getPendingConnections = function () {
|
|
239
|
+
return this.pendingConnections;
|
|
240
|
+
};
|
|
163
241
|
/**
|
|
164
242
|
* Returns the {@link ClientConnection} with given {@link Address}. If there is no such connection established,
|
|
165
243
|
* it first connects to the address and then return the {@link ClientConnection}.
|
|
@@ -98,7 +98,15 @@ export declare class ClusterService {
|
|
|
98
98
|
private handleMemberAttributeChange(uuid, key, operationType, value);
|
|
99
99
|
private memberAdded(member);
|
|
100
100
|
private memberRemoved(member);
|
|
101
|
+
/**
|
|
102
|
+
* Logs the current state for debugging purposes
|
|
103
|
+
*/
|
|
104
|
+
private logCurrentState();
|
|
101
105
|
private startReconnectionTask();
|
|
106
|
+
/**
|
|
107
|
+
* Starts a periodic task to log the current state for debugging
|
|
108
|
+
*/
|
|
109
|
+
private startStateLoggingTask();
|
|
102
110
|
private attemptReconnectionToFailedNodes();
|
|
103
111
|
/**
|
|
104
112
|
* Attempts to establish a connection to a specific address
|
|
@@ -57,6 +57,7 @@ var ClusterService = /** @class */ (function () {
|
|
|
57
57
|
this.logger = this.client.getLoggingService().getLogger();
|
|
58
58
|
this.members = [];
|
|
59
59
|
this.startReconnectionTask();
|
|
60
|
+
this.startStateLoggingTask();
|
|
60
61
|
}
|
|
61
62
|
/**
|
|
62
63
|
* Starts cluster service.
|
|
@@ -227,15 +228,21 @@ var ClusterService = /** @class */ (function () {
|
|
|
227
228
|
this.failoverInProgress = true;
|
|
228
229
|
this.lastFailoverAttempt = now;
|
|
229
230
|
this.logger.info('ClusterService', 'Starting failover process...');
|
|
231
|
+
// Log state before failover
|
|
232
|
+
this.logCurrentState();
|
|
233
|
+
// Force cleanup of all dead connections to prevent leakage
|
|
234
|
+
this.client.getConnectionManager().forceCleanupDeadConnections();
|
|
230
235
|
// Clear any stale partition information
|
|
231
236
|
this.client.getPartitionService().clearPartitionTable();
|
|
232
237
|
// Attempt to reconnect to cluster
|
|
233
238
|
this.connectToCluster()
|
|
234
239
|
.then(function () {
|
|
235
240
|
_this.logger.info('ClusterService', 'Failover completed successfully');
|
|
241
|
+
_this.logCurrentState(); // Log state after successful failover
|
|
236
242
|
})
|
|
237
243
|
.catch(function (error) {
|
|
238
244
|
_this.logger.error('ClusterService', 'Failover failed', error);
|
|
245
|
+
_this.logCurrentState(); // Log state after failed failover
|
|
239
246
|
// If failover fails, shutdown the client to prevent further issues
|
|
240
247
|
_this.client.shutdown();
|
|
241
248
|
})
|
|
@@ -349,6 +356,8 @@ var ClusterService = /** @class */ (function () {
|
|
|
349
356
|
this.members = members;
|
|
350
357
|
this.client.getPartitionService().refresh();
|
|
351
358
|
this.logger.info('ClusterService', 'Members received.', this.members);
|
|
359
|
+
// Log current state after member list update
|
|
360
|
+
this.logCurrentState();
|
|
352
361
|
var events = this.detectMembershipEvents(prevMembers);
|
|
353
362
|
for (var _i = 0, events_1 = events; _i < events_1.length; _i++) {
|
|
354
363
|
var event = events_1[_i];
|
|
@@ -416,10 +425,55 @@ var ClusterService = /** @class */ (function () {
|
|
|
416
425
|
var removedMemberList = this.members.splice(memberIndex, 1);
|
|
417
426
|
assert(removedMemberList.length === 1);
|
|
418
427
|
}
|
|
419
|
-
this
|
|
428
|
+
// Check if we have a healthy connection to this member
|
|
429
|
+
var connectionManager = this.client.getConnectionManager();
|
|
430
|
+
var existingConnection = connectionManager.getConnection(member.address);
|
|
431
|
+
if (existingConnection && existingConnection.isHealthy()) {
|
|
432
|
+
// If the connection is healthy, don't destroy it immediately
|
|
433
|
+
// This prevents unnecessary disconnections during temporary network issues
|
|
434
|
+
this.logger.info('ClusterService', "Member removed but connection is healthy: " + member.address.toString() + ", preserving connection");
|
|
435
|
+
// Only destroy if we're not in failover mode
|
|
436
|
+
if (!this.failoverInProgress) {
|
|
437
|
+
this.logger.debug('ClusterService', "Destroying healthy connection to removed member: " + member.address.toString());
|
|
438
|
+
connectionManager.destroyConnection(member.address);
|
|
439
|
+
}
|
|
440
|
+
else {
|
|
441
|
+
this.logger.debug('ClusterService', "Preserving healthy connection during failover: " + member.address.toString());
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
445
|
+
// If connection is unhealthy, destroy it
|
|
446
|
+
this.logger.info('ClusterService', "Member removed with unhealthy connection: " + member.address.toString() + ", destroying connection");
|
|
447
|
+
connectionManager.destroyConnection(member.address);
|
|
448
|
+
}
|
|
420
449
|
var membershipEvent = new MembershipEvent_1.MembershipEvent(member, MemberEvent.REMOVED, this.members);
|
|
421
450
|
this.fireMembershipEvent(membershipEvent);
|
|
422
451
|
};
|
|
452
|
+
/**
|
|
453
|
+
* Logs the current state for debugging purposes
|
|
454
|
+
*/
|
|
455
|
+
ClusterService.prototype.logCurrentState = function () {
|
|
456
|
+
var _this = this;
|
|
457
|
+
var activeConnections = Object.keys(this.client.getConnectionManager().getEstablishedConnections()).length;
|
|
458
|
+
var memberCount = this.members.length;
|
|
459
|
+
var downAddressesCount = this.downAddresses.size;
|
|
460
|
+
var hasOwner = !!this.ownerConnection;
|
|
461
|
+
this.logger.info('ClusterService', "Current State - Members: " + memberCount + ", Active Connections: " + activeConnections + ", Down Addresses: " + downAddressesCount + ", Has Owner: " + hasOwner);
|
|
462
|
+
if (this.ownerConnection) {
|
|
463
|
+
this.logger.info('ClusterService', "Owner Connection: " + this.ownerConnection.getAddress().toString() + ", Alive: " + this.ownerConnection.isAlive());
|
|
464
|
+
}
|
|
465
|
+
// Log all active connections
|
|
466
|
+
var connections = this.client.getConnectionManager().getEstablishedConnections();
|
|
467
|
+
Object.keys(connections).forEach(function (addressStr) {
|
|
468
|
+
var connection = connections[addressStr];
|
|
469
|
+
_this.logger.debug('ClusterService', "Connection to " + addressStr + ": Alive=" + connection.isAlive() + ", Owner=" + connection.isAuthenticatedAsOwner());
|
|
470
|
+
});
|
|
471
|
+
// Log down addresses
|
|
472
|
+
if (downAddressesCount > 0) {
|
|
473
|
+
var downAddresses = Array.from(this.downAddresses.keys());
|
|
474
|
+
this.logger.debug('ClusterService', "Down Addresses: " + downAddresses.join(', '));
|
|
475
|
+
}
|
|
476
|
+
};
|
|
423
477
|
ClusterService.prototype.startReconnectionTask = function () {
|
|
424
478
|
var _this = this;
|
|
425
479
|
// Periodically attempt to reconnect to previously failed addresses
|
|
@@ -427,15 +481,29 @@ var ClusterService = /** @class */ (function () {
|
|
|
427
481
|
_this.attemptReconnectionToFailedNodes();
|
|
428
482
|
}, this.reconnectionInterval);
|
|
429
483
|
};
|
|
484
|
+
/**
|
|
485
|
+
* Starts a periodic task to log the current state for debugging
|
|
486
|
+
*/
|
|
487
|
+
ClusterService.prototype.startStateLoggingTask = function () {
|
|
488
|
+
var _this = this;
|
|
489
|
+
// Log state every 30 seconds for debugging
|
|
490
|
+
setInterval(function () {
|
|
491
|
+
if (_this.client.getLifecycleService().isRunning()) {
|
|
492
|
+
_this.logCurrentState();
|
|
493
|
+
}
|
|
494
|
+
}, 30000);
|
|
495
|
+
};
|
|
430
496
|
ClusterService.prototype.attemptReconnectionToFailedNodes = function () {
|
|
431
497
|
var _this = this;
|
|
432
|
-
|
|
498
|
+
// Allow reconnection even during failover, but be more careful
|
|
499
|
+
if (this.failoverInProgress) {
|
|
500
|
+
this.logger.debug('ClusterService', 'Skipping reconnection attempt during failover');
|
|
433
501
|
return;
|
|
434
502
|
}
|
|
435
503
|
var now = Date.now();
|
|
436
504
|
var addressesToReconnect = [];
|
|
437
505
|
var totalDownAddresses = this.downAddresses.size;
|
|
438
|
-
// If we have no down addresses, we can
|
|
506
|
+
// If we have no down addresses, we can skip
|
|
439
507
|
if (totalDownAddresses === 0) {
|
|
440
508
|
return;
|
|
441
509
|
}
|
|
@@ -449,6 +517,12 @@ var ClusterService = /** @class */ (function () {
|
|
|
449
517
|
var port = parseInt(portStr, 10);
|
|
450
518
|
if (host && !isNaN(port)) {
|
|
451
519
|
var address = new Address(host, port);
|
|
520
|
+
// Check if we already have a connection to this address
|
|
521
|
+
if (_this.client.getConnectionManager().hasConnection(address)) {
|
|
522
|
+
_this.logger.debug('ClusterService', "Already have active connection to " + addressStr + ", removing from down addresses");
|
|
523
|
+
_this.downAddresses.delete(addressStr);
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
452
526
|
addressesToReconnect.push(address);
|
|
453
527
|
}
|
|
454
528
|
}
|
|
@@ -474,6 +548,8 @@ var ClusterService = /** @class */ (function () {
|
|
|
474
548
|
});
|
|
475
549
|
this.logger.debug('ClusterService', "Still waiting for " + totalDownAddresses + " addresses to unblock: " + remainingBlocked.join(', '));
|
|
476
550
|
}
|
|
551
|
+
// Log current state after reconnection attempts
|
|
552
|
+
this.logCurrentState();
|
|
477
553
|
};
|
|
478
554
|
/**
|
|
479
555
|
* Attempts to establish a connection to a specific address
|
|
@@ -482,6 +558,20 @@ var ClusterService = /** @class */ (function () {
|
|
|
482
558
|
ClusterService.prototype.attemptReconnectionToAddress = function (address) {
|
|
483
559
|
var _this = this;
|
|
484
560
|
var addressStr = address.toString();
|
|
561
|
+
// Check if we already have a connection to this address
|
|
562
|
+
if (this.client.getConnectionManager().hasConnection(address)) {
|
|
563
|
+
this.logger.debug('ClusterService', "Already have active connection to " + addressStr + ", skipping reconnection");
|
|
564
|
+
this.downAddresses.delete(addressStr);
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
// Check if we're already trying to connect to this address
|
|
568
|
+
var connectionManager = this.client.getConnectionManager();
|
|
569
|
+
var establishedConnections = connectionManager.getEstablishedConnections();
|
|
570
|
+
var pendingConnections = Object.keys(connectionManager.getPendingConnections || {}).length;
|
|
571
|
+
if (pendingConnections > 0) {
|
|
572
|
+
this.logger.debug('ClusterService', "Already have pending connections, skipping reconnection to " + addressStr);
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
485
575
|
// Remove from down addresses to allow connection attempt
|
|
486
576
|
this.downAddresses.delete(addressStr);
|
|
487
577
|
this.logger.debug('ClusterService', "Attempting reconnection to " + addressStr);
|
|
@@ -489,8 +579,14 @@ var ClusterService = /** @class */ (function () {
|
|
|
489
579
|
this.client.getConnectionManager().getOrConnect(address, false)
|
|
490
580
|
.then(function (connection) {
|
|
491
581
|
_this.logger.info('ClusterService', "Successfully reconnected to " + addressStr);
|
|
492
|
-
//
|
|
493
|
-
_this.
|
|
582
|
+
// Only evaluate ownership change if we don't have an owner or current owner is unhealthy
|
|
583
|
+
if (!_this.ownerConnection || !_this.ownerConnection.isHealthy()) {
|
|
584
|
+
_this.logger.info('ClusterService', "Evaluating ownership change for " + addressStr);
|
|
585
|
+
_this.evaluateOwnershipChange(address, connection);
|
|
586
|
+
}
|
|
587
|
+
else {
|
|
588
|
+
_this.logger.debug('ClusterService', "Keeping " + addressStr + " as member connection, current owner is healthy");
|
|
589
|
+
}
|
|
494
590
|
// Trigger partition service refresh to update routing information
|
|
495
591
|
_this.client.getPartitionService().refresh();
|
|
496
592
|
}).catch(function (error) {
|
|
@@ -518,12 +614,8 @@ var ClusterService = /** @class */ (function () {
|
|
|
518
614
|
this.promoteToOwner(connection, address);
|
|
519
615
|
return;
|
|
520
616
|
}
|
|
521
|
-
//
|
|
522
|
-
|
|
523
|
-
if (wasPreviousOwner) {
|
|
524
|
-
this.logger.debug('ClusterService', "Reconnected node " + address.toString() + " was previously known, monitoring for ownership opportunity");
|
|
525
|
-
// Don't switch ownership immediately, but keep the connection for potential future use
|
|
526
|
-
}
|
|
617
|
+
// Don't switch ownership if current owner is healthy
|
|
618
|
+
this.logger.debug('ClusterService', "Current owner is healthy, keeping " + address.toString() + " as member connection");
|
|
527
619
|
};
|
|
528
620
|
/**
|
|
529
621
|
* Promotes a connection to owner status
|
package/package.json
CHANGED