@celerispay/hazelcast-client 3.12.5-1 → 3.12.5-2

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.
@@ -36,6 +36,25 @@ 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
+ * Gets an existing connection to a specific address if it exists
47
+ * @param address The address to check for existing connection
48
+ * @returns The existing connection or undefined if none exists
49
+ */
50
+ getConnection(address: Address): ClientConnection | undefined;
51
+ /**
52
+ * Gets all established connections
53
+ * @returns Object containing all established connections
54
+ */
55
+ getEstablishedConnections(): {
56
+ [address: string]: ClientConnection;
57
+ };
39
58
  /**
40
59
  * Returns the {@link ClientConnection} with given {@link Address}. If there is no such connection established,
41
60
  * 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
@@ -160,6 +171,32 @@ 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
+ * Gets an existing connection to a specific address if it exists
186
+ * @param address The address to check for existing connection
187
+ * @returns The existing connection or undefined if none exists
188
+ */
189
+ ClientConnectionManager.prototype.getConnection = function (address) {
190
+ var addressStr = address.toString();
191
+ return this.establishedConnections[addressStr];
192
+ };
193
+ /**
194
+ * Gets all established connections
195
+ * @returns Object containing all established connections
196
+ */
197
+ ClientConnectionManager.prototype.getEstablishedConnections = function () {
198
+ return this.establishedConnections;
199
+ };
163
200
  /**
164
201
  * Returns the {@link ClientConnection} with given {@link Address}. If there is no such connection established,
165
202
  * 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,19 @@ 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();
230
233
  // Clear any stale partition information
231
234
  this.client.getPartitionService().clearPartitionTable();
232
235
  // Attempt to reconnect to cluster
233
236
  this.connectToCluster()
234
237
  .then(function () {
235
238
  _this.logger.info('ClusterService', 'Failover completed successfully');
239
+ _this.logCurrentState(); // Log state after successful failover
236
240
  })
237
241
  .catch(function (error) {
238
242
  _this.logger.error('ClusterService', 'Failover failed', error);
243
+ _this.logCurrentState(); // Log state after failed failover
239
244
  // If failover fails, shutdown the client to prevent further issues
240
245
  _this.client.shutdown();
241
246
  })
@@ -349,6 +354,8 @@ var ClusterService = /** @class */ (function () {
349
354
  this.members = members;
350
355
  this.client.getPartitionService().refresh();
351
356
  this.logger.info('ClusterService', 'Members received.', this.members);
357
+ // Log current state after member list update
358
+ this.logCurrentState();
352
359
  var events = this.detectMembershipEvents(prevMembers);
353
360
  for (var _i = 0, events_1 = events; _i < events_1.length; _i++) {
354
361
  var event = events_1[_i];
@@ -416,10 +423,42 @@ var ClusterService = /** @class */ (function () {
416
423
  var removedMemberList = this.members.splice(memberIndex, 1);
417
424
  assert(removedMemberList.length === 1);
418
425
  }
419
- this.client.getConnectionManager().destroyConnection(member.address);
426
+ // Don't automatically destroy connections during failover
427
+ if (!this.failoverInProgress) {
428
+ this.logger.info('ClusterService', "Member removed: " + member.address.toString() + ", destroying connection");
429
+ this.client.getConnectionManager().destroyConnection(member.address);
430
+ }
431
+ else {
432
+ this.logger.debug('ClusterService', "Member removed during failover: " + member.address.toString() + ", keeping connection for evaluation");
433
+ }
420
434
  var membershipEvent = new MembershipEvent_1.MembershipEvent(member, MemberEvent.REMOVED, this.members);
421
435
  this.fireMembershipEvent(membershipEvent);
422
436
  };
437
+ /**
438
+ * Logs the current state for debugging purposes
439
+ */
440
+ ClusterService.prototype.logCurrentState = function () {
441
+ var _this = this;
442
+ var activeConnections = Object.keys(this.client.getConnectionManager().getEstablishedConnections()).length;
443
+ var memberCount = this.members.length;
444
+ var downAddressesCount = this.downAddresses.size;
445
+ var hasOwner = !!this.ownerConnection;
446
+ this.logger.info('ClusterService', "Current State - Members: " + memberCount + ", Active Connections: " + activeConnections + ", Down Addresses: " + downAddressesCount + ", Has Owner: " + hasOwner);
447
+ if (this.ownerConnection) {
448
+ this.logger.info('ClusterService', "Owner Connection: " + this.ownerConnection.getAddress().toString() + ", Alive: " + this.ownerConnection.isAlive());
449
+ }
450
+ // Log all active connections
451
+ var connections = this.client.getConnectionManager().getEstablishedConnections();
452
+ Object.keys(connections).forEach(function (addressStr) {
453
+ var connection = connections[addressStr];
454
+ _this.logger.debug('ClusterService', "Connection to " + addressStr + ": Alive=" + connection.isAlive() + ", Owner=" + connection.isAuthenticatedAsOwner());
455
+ });
456
+ // Log down addresses
457
+ if (downAddressesCount > 0) {
458
+ var downAddresses = Array.from(this.downAddresses.keys());
459
+ this.logger.debug('ClusterService', "Down Addresses: " + downAddresses.join(', '));
460
+ }
461
+ };
423
462
  ClusterService.prototype.startReconnectionTask = function () {
424
463
  var _this = this;
425
464
  // Periodically attempt to reconnect to previously failed addresses
@@ -427,15 +466,29 @@ var ClusterService = /** @class */ (function () {
427
466
  _this.attemptReconnectionToFailedNodes();
428
467
  }, this.reconnectionInterval);
429
468
  };
469
+ /**
470
+ * Starts a periodic task to log the current state for debugging
471
+ */
472
+ ClusterService.prototype.startStateLoggingTask = function () {
473
+ var _this = this;
474
+ // Log state every 30 seconds for debugging
475
+ setInterval(function () {
476
+ if (_this.client.getLifecycleService().isRunning()) {
477
+ _this.logCurrentState();
478
+ }
479
+ }, 30000);
480
+ };
430
481
  ClusterService.prototype.attemptReconnectionToFailedNodes = function () {
431
482
  var _this = this;
432
- if (this.failoverInProgress || !this.ownerConnection) {
483
+ // Allow reconnection even during failover, but be more careful
484
+ if (this.failoverInProgress) {
485
+ this.logger.debug('ClusterService', 'Skipping reconnection attempt during failover');
433
486
  return;
434
487
  }
435
488
  var now = Date.now();
436
489
  var addressesToReconnect = [];
437
490
  var totalDownAddresses = this.downAddresses.size;
438
- // If we have no down addresses, we can increase the reconnection interval
491
+ // If we have no down addresses, we can skip
439
492
  if (totalDownAddresses === 0) {
440
493
  return;
441
494
  }
@@ -449,6 +502,12 @@ var ClusterService = /** @class */ (function () {
449
502
  var port = parseInt(portStr, 10);
450
503
  if (host && !isNaN(port)) {
451
504
  var address = new Address(host, port);
505
+ // Check if we already have a connection to this address
506
+ if (_this.client.getConnectionManager().hasConnection(address)) {
507
+ _this.logger.debug('ClusterService', "Already have active connection to " + addressStr + ", removing from down addresses");
508
+ _this.downAddresses.delete(addressStr);
509
+ return;
510
+ }
452
511
  addressesToReconnect.push(address);
453
512
  }
454
513
  }
@@ -474,6 +533,8 @@ var ClusterService = /** @class */ (function () {
474
533
  });
475
534
  this.logger.debug('ClusterService', "Still waiting for " + totalDownAddresses + " addresses to unblock: " + remainingBlocked.join(', '));
476
535
  }
536
+ // Log current state after reconnection attempts
537
+ this.logCurrentState();
477
538
  };
478
539
  /**
479
540
  * Attempts to establish a connection to a specific address
@@ -482,6 +543,12 @@ var ClusterService = /** @class */ (function () {
482
543
  ClusterService.prototype.attemptReconnectionToAddress = function (address) {
483
544
  var _this = this;
484
545
  var addressStr = address.toString();
546
+ // Check if we already have a connection to this address
547
+ if (this.client.getConnectionManager().hasConnection(address)) {
548
+ this.logger.debug('ClusterService', "Already have active connection to " + addressStr + ", skipping reconnection");
549
+ this.downAddresses.delete(addressStr);
550
+ return;
551
+ }
485
552
  // Remove from down addresses to allow connection attempt
486
553
  this.downAddresses.delete(addressStr);
487
554
  this.logger.debug('ClusterService', "Attempting reconnection to " + addressStr);
@@ -489,8 +556,14 @@ var ClusterService = /** @class */ (function () {
489
556
  this.client.getConnectionManager().getOrConnect(address, false)
490
557
  .then(function (connection) {
491
558
  _this.logger.info('ClusterService', "Successfully reconnected to " + addressStr);
492
- // Check if this reconnected node should become the new owner
493
- _this.evaluateOwnershipChange(address, connection);
559
+ // Only evaluate ownership change if we don't have an owner or current owner is unhealthy
560
+ if (!_this.ownerConnection || !_this.ownerConnection.isAlive()) {
561
+ _this.logger.info('ClusterService', "Evaluating ownership change for " + addressStr);
562
+ _this.evaluateOwnershipChange(address, connection);
563
+ }
564
+ else {
565
+ _this.logger.debug('ClusterService', "Keeping " + addressStr + " as member connection, current owner is healthy");
566
+ }
494
567
  // Trigger partition service refresh to update routing information
495
568
  _this.client.getPartitionService().refresh();
496
569
  }).catch(function (error) {
@@ -518,12 +591,8 @@ var ClusterService = /** @class */ (function () {
518
591
  this.promoteToOwner(connection, address);
519
592
  return;
520
593
  }
521
- // Check if this reconnected node was previously our owner (by checking if it's in our known addresses)
522
- var wasPreviousOwner = this.knownAddresses.some(function (knownAddr) { return knownAddr.equals(address); });
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
- }
594
+ // Don't switch ownership if current owner is healthy
595
+ this.logger.debug('ClusterService', "Current owner is healthy, keeping " + address.toString() + " as member connection");
527
596
  };
528
597
  /**
529
598
  * Promotes a connection to owner status
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@celerispay/hazelcast-client",
3
- "version": "3.12.5-1",
3
+ "version": "3.12.5-2",
4
4
  "description": "Hazelcast - open source In-Memory Data Grid - client for NodeJS with critical connection failover fixes",
5
5
  "main": "./lib/index.js",
6
6
  "scripts": {