@celerispay/hazelcast-client 3.12.5-4 → 3.12.5-5
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.
|
@@ -82,9 +82,14 @@ export declare class ClientConnectionManager extends EventEmitter {
|
|
|
82
82
|
destroyConnection(address: Address): void;
|
|
83
83
|
/**
|
|
84
84
|
* Cleans up all connections to a specific address during failover
|
|
85
|
-
* @param address
|
|
85
|
+
* @param address The address to cleanup
|
|
86
86
|
*/
|
|
87
87
|
cleanupConnectionsForFailover(address: Address): void;
|
|
88
|
+
/**
|
|
89
|
+
* Handles authentication errors by clearing failed connections and allowing retry
|
|
90
|
+
* @param address The address that had authentication issues
|
|
91
|
+
*/
|
|
92
|
+
handleAuthenticationError(address: Address): void;
|
|
88
93
|
shutdown(): void;
|
|
89
94
|
private triggerConnect(address, asOwner);
|
|
90
95
|
private connectTLSSocket(address, configOpts);
|
|
@@ -133,6 +133,16 @@ var ClientConnectionManager = /** @class */ (function (_super) {
|
|
|
133
133
|
_this.failedConnections.delete(address.toString());
|
|
134
134
|
return connection;
|
|
135
135
|
}).catch(function (error) {
|
|
136
|
+
// Check if it's an authentication error
|
|
137
|
+
var isAuthError = error.message && (error.message.includes('Invalid Credentials') ||
|
|
138
|
+
error.message.includes('authentication') ||
|
|
139
|
+
error.message.includes('credentials'));
|
|
140
|
+
if (isAuthError) {
|
|
141
|
+
_this.logger.error('ClientConnectionManager', "Authentication failed for " + address.toString() + ", not retrying: " + error.message);
|
|
142
|
+
// Handle authentication errors specially
|
|
143
|
+
_this.handleAuthenticationError(address);
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
136
146
|
if (retryCount < _this.maxConnectionRetries) {
|
|
137
147
|
_this.logger.warn('ClientConnectionManager', "Connection attempt " + (retryCount + 1) + " failed for " + address.toString() + ", retrying in " + _this.connectionRetryDelay + "ms");
|
|
138
148
|
return new Promise(function (resolve, reject) {
|
|
@@ -328,7 +338,7 @@ var ClientConnectionManager = /** @class */ (function (_super) {
|
|
|
328
338
|
};
|
|
329
339
|
/**
|
|
330
340
|
* Cleans up all connections to a specific address during failover
|
|
331
|
-
* @param address
|
|
341
|
+
* @param address The address to cleanup
|
|
332
342
|
*/
|
|
333
343
|
ClientConnectionManager.prototype.cleanupConnectionsForFailover = function (address) {
|
|
334
344
|
var addressStr = address.toString();
|
|
@@ -338,6 +348,27 @@ var ClientConnectionManager = /** @class */ (function (_super) {
|
|
|
338
348
|
// Remove from failed connections to allow reconnection after failover
|
|
339
349
|
this.failedConnections.delete(addressStr);
|
|
340
350
|
};
|
|
351
|
+
/**
|
|
352
|
+
* Handles authentication errors by clearing failed connections and allowing retry
|
|
353
|
+
* @param address The address that had authentication issues
|
|
354
|
+
*/
|
|
355
|
+
ClientConnectionManager.prototype.handleAuthenticationError = function (address) {
|
|
356
|
+
var addressStr = address.toString();
|
|
357
|
+
this.logger.warn('ClientConnectionManager', "Handling authentication error for " + addressStr);
|
|
358
|
+
// Clear from failed connections to allow retry with fresh credentials
|
|
359
|
+
this.failedConnections.delete(addressStr);
|
|
360
|
+
// Also clear any established connections to this address
|
|
361
|
+
if (this.establishedConnections.hasOwnProperty(addressStr)) {
|
|
362
|
+
this.logger.info('ClientConnectionManager', "Clearing established connection to " + addressStr + " due to auth error");
|
|
363
|
+
this.destroyConnection(address);
|
|
364
|
+
}
|
|
365
|
+
// Clear any pending connections
|
|
366
|
+
if (this.pendingConnections.hasOwnProperty(addressStr)) {
|
|
367
|
+
this.logger.info('ClientConnectionManager', "Clearing pending connection to " + addressStr + " due to auth error");
|
|
368
|
+
this.pendingConnections[addressStr].reject(new Error('Authentication error, connection cleared'));
|
|
369
|
+
delete this.pendingConnections[addressStr];
|
|
370
|
+
}
|
|
371
|
+
};
|
|
341
372
|
ClientConnectionManager.prototype.shutdown = function () {
|
|
342
373
|
if (this.connectionHealthCheckInterval) {
|
|
343
374
|
clearInterval(this.connectionHealthCheckInterval);
|
|
@@ -87,6 +87,10 @@ export declare class ClusterService {
|
|
|
87
87
|
private onConnectionClosed(connection);
|
|
88
88
|
private onHeartbeatStopped(connection);
|
|
89
89
|
private triggerFailover();
|
|
90
|
+
/**
|
|
91
|
+
* Attempts emergency recovery when failover fails
|
|
92
|
+
*/
|
|
93
|
+
private attemptEmergencyRecovery();
|
|
90
94
|
private isAddressKnownDown(address);
|
|
91
95
|
private markAddressAsDown(address);
|
|
92
96
|
private getDownAddressesInfo();
|
|
@@ -50,7 +50,7 @@ var ClusterService = /** @class */ (function () {
|
|
|
50
50
|
this.lastFailoverAttempt = 0;
|
|
51
51
|
this.failoverCooldown = 5000; // 5 seconds cooldown between failover attempts
|
|
52
52
|
this.downAddresses = new Map(); // address -> timestamp when marked down
|
|
53
|
-
this.addressBlockDuration =
|
|
53
|
+
this.addressBlockDuration = 15000; // Reduced from 30000ms to 15000ms
|
|
54
54
|
this.reconnectionTask = null;
|
|
55
55
|
this.reconnectionInterval = 10000; // 10 seconds between reconnection attempts
|
|
56
56
|
this.client = client;
|
|
@@ -242,14 +242,50 @@ var ClusterService = /** @class */ (function () {
|
|
|
242
242
|
})
|
|
243
243
|
.catch(function (error) {
|
|
244
244
|
_this.logger.error('ClusterService', 'Failover failed', error);
|
|
245
|
+
// If failover fails, try to unblock at least one address to allow recovery
|
|
246
|
+
_this.attemptEmergencyRecovery();
|
|
245
247
|
_this.logCurrentState(); // Log state after failed failover
|
|
246
|
-
//
|
|
247
|
-
_this.client.shutdown();
|
|
248
|
+
// Don't shutdown immediately, give recovery a chance
|
|
248
249
|
})
|
|
249
250
|
.finally(function () {
|
|
250
251
|
_this.failoverInProgress = false;
|
|
251
252
|
});
|
|
252
253
|
};
|
|
254
|
+
/**
|
|
255
|
+
* Attempts emergency recovery when failover fails
|
|
256
|
+
*/
|
|
257
|
+
ClusterService.prototype.attemptEmergencyRecovery = function () {
|
|
258
|
+
var _this = this;
|
|
259
|
+
this.logger.warn('ClusterService', 'Attempting emergency recovery...');
|
|
260
|
+
// Unblock at least one address to allow recovery
|
|
261
|
+
if (this.downAddresses.size > 0) {
|
|
262
|
+
var firstBlockedAddress_1 = Array.from(this.downAddresses.keys())[0];
|
|
263
|
+
this.logger.info('ClusterService', "Emergency unblocking address " + firstBlockedAddress_1);
|
|
264
|
+
this.downAddresses.delete(firstBlockedAddress_1);
|
|
265
|
+
// Try to connect to the unblocked address
|
|
266
|
+
try {
|
|
267
|
+
var _a = firstBlockedAddress_1.split(':'), host = _a[0], portStr = _a[1];
|
|
268
|
+
var port = parseInt(portStr, 10);
|
|
269
|
+
if (host && !isNaN(port)) {
|
|
270
|
+
var address_1 = new Address(host, port);
|
|
271
|
+
this.logger.info('ClusterService', "Attempting emergency connection to " + firstBlockedAddress_1);
|
|
272
|
+
// Try to connect without blocking
|
|
273
|
+
this.client.getConnectionManager().getOrConnect(address_1, false)
|
|
274
|
+
.then(function (connection) {
|
|
275
|
+
_this.logger.info('ClusterService', "Emergency connection successful to " + firstBlockedAddress_1);
|
|
276
|
+
_this.evaluateOwnershipChange(address_1, connection);
|
|
277
|
+
_this.client.getPartitionService().refresh();
|
|
278
|
+
})
|
|
279
|
+
.catch(function (error) {
|
|
280
|
+
_this.logger.warn('ClusterService', "Emergency connection failed to " + firstBlockedAddress_1 + ":", error);
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
catch (error) {
|
|
285
|
+
this.logger.error('ClusterService', 'Error during emergency recovery:', error);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
};
|
|
253
289
|
ClusterService.prototype.isAddressKnownDown = function (address) {
|
|
254
290
|
var addressStr = address.toString();
|
|
255
291
|
var downTime = this.downAddresses.get(addressStr);
|
|
@@ -651,6 +687,18 @@ var ClusterService = /** @class */ (function () {
|
|
|
651
687
|
var _this = this;
|
|
652
688
|
var addressStr = address.toString();
|
|
653
689
|
var now = Date.now();
|
|
690
|
+
// Don't block if we already have a healthy connection to this address
|
|
691
|
+
if (this.client.getConnectionManager().hasConnection(address)) {
|
|
692
|
+
this.logger.debug('ClusterService', "Not blocking " + addressStr + " as we have a healthy connection");
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
// Don't block if this would leave us with no available nodes
|
|
696
|
+
var totalDownAddresses = this.downAddresses.size;
|
|
697
|
+
var totalMembers = this.members.length;
|
|
698
|
+
if (totalDownAddresses >= totalMembers - 1) {
|
|
699
|
+
this.logger.warn('ClusterService', "Not blocking " + addressStr + " as it would leave us with no available nodes");
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
654
702
|
this.downAddresses.set(addressStr, now);
|
|
655
703
|
this.logger.warn('ClusterService', "Marked address " + addressStr + " as down, will be blocked for " + blockDuration + "ms");
|
|
656
704
|
// Schedule cleanup of this address after block duration
|
package/package.json
CHANGED