@celerispay/hazelcast-client 3.12.5-8 → 3.12.7-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.
- package/CHANGES_UNCOMMITTED.md +53 -0
- package/FAULT_TOLERANCE_IMPROVEMENTS.md +208 -0
- package/HAZELCAST_CLIENT_EVOLUTION.md +402 -0
- package/lib/HeartbeatService.js +11 -2
- package/lib/PartitionService.d.ts +0 -3
- package/lib/PartitionService.js +3 -32
- package/lib/invocation/ClientConnection.js +41 -11
- package/lib/invocation/ClientConnectionManager.d.ts +54 -0
- package/lib/invocation/ClientConnectionManager.js +210 -4
- package/lib/invocation/ClusterService.d.ts +47 -0
- package/lib/invocation/ClusterService.js +164 -4
- package/lib/invocation/ConnectionAuthenticator.d.ts +11 -0
- package/lib/invocation/ConnectionAuthenticator.js +85 -12
- package/lib/invocation/CredentialPreservationService.d.ts +141 -0
- package/lib/invocation/CredentialPreservationService.js +377 -0
- package/lib/invocation/HazelcastFailoverManager.d.ts +102 -0
- package/lib/invocation/HazelcastFailoverManager.js +285 -0
- package/package.json +7 -6
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2008-2021, Hazelcast, Inc. All Rights Reserved.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
/**
|
|
19
|
+
* Service to preserve and restore authentication credentials across failover cycles
|
|
20
|
+
* This fixes the "Invalid Credentials" issue that occurs when nodes rejoin after failover
|
|
21
|
+
*/
|
|
22
|
+
var CredentialPreservationService = /** @class */ (function () {
|
|
23
|
+
function CredentialPreservationService(logger) {
|
|
24
|
+
/**
|
|
25
|
+
* Stores authentication context for each node
|
|
26
|
+
*/
|
|
27
|
+
this.nodeCredentials = new Map();
|
|
28
|
+
this.logger = logger;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Preserves authentication credentials for a node before it gets disconnected
|
|
32
|
+
* @param address The node address
|
|
33
|
+
* @param uuid The node's UUID
|
|
34
|
+
* @param ownerUuid The owner UUID
|
|
35
|
+
* @param groupName The group name
|
|
36
|
+
* @param groupPassword The group password
|
|
37
|
+
* @param isOwner Whether this is an owner connection
|
|
38
|
+
*/
|
|
39
|
+
CredentialPreservationService.prototype.preserveCredentials = function (address, uuid, ownerUuid, groupName, groupPassword, isOwner) {
|
|
40
|
+
var addressStr = address.toString();
|
|
41
|
+
this.nodeCredentials.set(addressStr, {
|
|
42
|
+
uuid: uuid,
|
|
43
|
+
ownerUuid: ownerUuid,
|
|
44
|
+
groupName: groupName,
|
|
45
|
+
groupPassword: groupPassword,
|
|
46
|
+
lastAuthenticated: Date.now(),
|
|
47
|
+
isOwner: isOwner
|
|
48
|
+
});
|
|
49
|
+
this.logger.debug('CredentialPreservationService', "Preserved credentials for " + addressStr + ": uuid=" + uuid + ", ownerUuid=" + ownerUuid + ", isOwner=" + isOwner);
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Restores authentication credentials for a specific node
|
|
53
|
+
* @param address The node address
|
|
54
|
+
* @returns The preserved credentials or null if not found
|
|
55
|
+
*/
|
|
56
|
+
CredentialPreservationService.prototype.restoreCredentials = function (address) {
|
|
57
|
+
var _this = this;
|
|
58
|
+
var addressStr = address.toString();
|
|
59
|
+
var credentials = this.nodeCredentials.get(addressStr);
|
|
60
|
+
if (credentials) {
|
|
61
|
+
this.logger.info('CredentialPreservationService', "\u2705 Found preserved credentials for " + addressStr + ": uuid=" + credentials.uuid + ", ownerUuid=" + credentials.ownerUuid);
|
|
62
|
+
return credentials;
|
|
63
|
+
}
|
|
64
|
+
// Log all available credentials for debugging
|
|
65
|
+
this.logger.info('CredentialPreservationService', "\u274C No preserved credentials found for " + addressStr);
|
|
66
|
+
this.logger.info('CredentialPreservationService', "\uD83D\uDCCB Available credentials: " + this.nodeCredentials.size + " entries");
|
|
67
|
+
if (this.nodeCredentials.size > 0) {
|
|
68
|
+
this.nodeCredentials.forEach(function (cred, addr) {
|
|
69
|
+
_this.logger.info('CredentialPreservationService', " - " + addr + ": uuid=" + cred.uuid + ", ownerUuid=" + cred.ownerUuid + ", isOwner=" + cred.isOwner);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Updates credentials after successful authentication
|
|
76
|
+
* @param address The node address
|
|
77
|
+
* @param uuid The new UUID
|
|
78
|
+
* @param ownerUuid The new owner UUID
|
|
79
|
+
*/
|
|
80
|
+
CredentialPreservationService.prototype.updateCredentials = function (address, uuid, ownerUuid) {
|
|
81
|
+
var addressStr = address.toString();
|
|
82
|
+
var credentials = this.nodeCredentials.get(addressStr);
|
|
83
|
+
if (credentials) {
|
|
84
|
+
credentials.uuid = uuid;
|
|
85
|
+
credentials.ownerUuid = ownerUuid;
|
|
86
|
+
credentials.lastAuthenticated = Date.now();
|
|
87
|
+
this.logger.debug('CredentialPreservationService', "Updated credentials for " + addressStr + ": uuid=" + uuid + ", ownerUuid=" + ownerUuid);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Clears credentials for a specific node
|
|
92
|
+
* @param address The node address
|
|
93
|
+
*/
|
|
94
|
+
CredentialPreservationService.prototype.clearCredentials = function (address) {
|
|
95
|
+
var addressStr = address.toString();
|
|
96
|
+
if (this.nodeCredentials.delete(addressStr)) {
|
|
97
|
+
this.logger.debug('CredentialPreservationService', "Cleared credentials for " + addressStr);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Clears all stored credentials - used for cluster reset scenarios
|
|
102
|
+
*/
|
|
103
|
+
CredentialPreservationService.prototype.clearAllCredentials = function () {
|
|
104
|
+
var credentialCount = this.nodeCredentials.size;
|
|
105
|
+
this.nodeCredentials.clear();
|
|
106
|
+
this.logger.info('CredentialPreservationService', "\uD83E\uDDF9 Cleared all " + credentialCount + " stored credentials for cluster reset");
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Cleans up stale credentials older than the specified age
|
|
110
|
+
* @param maxAgeMs Maximum age in milliseconds (default: 5 minutes)
|
|
111
|
+
*/
|
|
112
|
+
CredentialPreservationService.prototype.cleanupStaleCredentials = function (maxAgeMs) {
|
|
113
|
+
var _this = this;
|
|
114
|
+
if (maxAgeMs === void 0) { maxAgeMs = 300000; }
|
|
115
|
+
var now = Date.now();
|
|
116
|
+
var addressesToRemove = [];
|
|
117
|
+
this.nodeCredentials.forEach(function (credentials, addressStr) {
|
|
118
|
+
var age = now - credentials.lastAuthenticated;
|
|
119
|
+
if (age > maxAgeMs) {
|
|
120
|
+
addressesToRemove.push(addressStr);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
if (addressesToRemove.length > 0) {
|
|
124
|
+
addressesToRemove.forEach(function (addressStr) {
|
|
125
|
+
_this.nodeCredentials.delete(addressStr);
|
|
126
|
+
});
|
|
127
|
+
this.logger.debug('CredentialPreservationService', "Cleaned up " + addressesToRemove.length + " stale credential entries");
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* Gets a summary of preserved credentials for debugging
|
|
132
|
+
* @returns A summary string
|
|
133
|
+
*/
|
|
134
|
+
CredentialPreservationService.prototype.getCredentialsSummary = function () {
|
|
135
|
+
var entries = Array.from(this.nodeCredentials.entries());
|
|
136
|
+
if (entries.length === 0) {
|
|
137
|
+
return 'none';
|
|
138
|
+
}
|
|
139
|
+
return entries.map(function (_a) {
|
|
140
|
+
var address = _a[0], creds = _a[1];
|
|
141
|
+
return address + ": uuid=" + (creds.uuid || 'null') + ", ownerUuid=" + (creds.ownerUuid || 'null') + ", isOwner=" + creds.isOwner;
|
|
142
|
+
}).join('; ');
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* Smart credential restoration that handles both scenarios:
|
|
146
|
+
* 1. If member added event occurred -> use new UUID
|
|
147
|
+
* 2. If no member added event -> use old UUID (node probably never changed)
|
|
148
|
+
* @param address The address to restore credentials for
|
|
149
|
+
* @param hasMemberAddedEvent Whether we received a member added event for this address
|
|
150
|
+
* @returns The appropriate credentials to use
|
|
151
|
+
*/
|
|
152
|
+
CredentialPreservationService.prototype.smartRestoreCredentials = function (address, hasMemberAddedEvent) {
|
|
153
|
+
if (hasMemberAddedEvent === void 0) { hasMemberAddedEvent = false; }
|
|
154
|
+
var addressStr = address.toString();
|
|
155
|
+
var credentials = this.nodeCredentials.get(addressStr);
|
|
156
|
+
if (!credentials) {
|
|
157
|
+
this.logger.debug('CredentialPreservationService', "No preserved credentials found for " + addressStr);
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
if (hasMemberAddedEvent) {
|
|
161
|
+
// Member actually left and rejoined - use the updated credentials
|
|
162
|
+
this.logger.info('CredentialPreservationService', "\uD83D\uDD04 Member added event detected for " + addressStr + ", using updated credentials: uuid=" + credentials.uuid);
|
|
163
|
+
return credentials;
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
// No member added event - node probably never changed, use original credentials
|
|
167
|
+
this.logger.info('CredentialPreservationService', "\uD83D\uDD04 No member added event for " + addressStr + ", assuming node unchanged, using original credentials: uuid=" + credentials.uuid);
|
|
168
|
+
return credentials;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
/**
|
|
172
|
+
* Checks if we have valid credentials for an address
|
|
173
|
+
* @param address The address to check
|
|
174
|
+
* @returns True if we have valid credentials
|
|
175
|
+
*/
|
|
176
|
+
CredentialPreservationService.prototype.hasValidCredentials = function (address) {
|
|
177
|
+
var addressStr = address.toString();
|
|
178
|
+
var credentials = this.nodeCredentials.get(addressStr);
|
|
179
|
+
return !!(credentials && credentials.uuid && credentials.ownerUuid);
|
|
180
|
+
};
|
|
181
|
+
/**
|
|
182
|
+
* Gets the last known UUID for an address
|
|
183
|
+
* @param address The address to get UUID for
|
|
184
|
+
* @returns The UUID or null if not found
|
|
185
|
+
*/
|
|
186
|
+
CredentialPreservationService.prototype.getLastKnownUuid = function (address) {
|
|
187
|
+
var addressStr = address.toString();
|
|
188
|
+
var credentials = this.nodeCredentials.get(addressStr);
|
|
189
|
+
return credentials ? credentials.uuid : null;
|
|
190
|
+
};
|
|
191
|
+
/**
|
|
192
|
+
* Updates the owner UUID for ALL preserved credentials
|
|
193
|
+
* This is called when cluster membership changes and we need to sync all credentials
|
|
194
|
+
* @param newOwnerUuid The new owner UUID from the current cluster state
|
|
195
|
+
*/
|
|
196
|
+
CredentialPreservationService.prototype.updateAllOwnerUuids = function (newOwnerUuid) {
|
|
197
|
+
var _this = this;
|
|
198
|
+
this.logger.info('CredentialPreservationService', "\uD83D\uDD04 Updating ALL preserved credentials with new owner UUID: " + newOwnerUuid);
|
|
199
|
+
var updatedCount = 0;
|
|
200
|
+
this.nodeCredentials.forEach(function (credentials, addressStr) {
|
|
201
|
+
if (credentials.ownerUuid !== newOwnerUuid) {
|
|
202
|
+
var oldOwnerUuid = credentials.ownerUuid;
|
|
203
|
+
credentials.ownerUuid = newOwnerUuid;
|
|
204
|
+
updatedCount++;
|
|
205
|
+
_this.logger.info('CredentialPreservationService', "\uD83D\uDD04 Updated " + addressStr + ": ownerUuid " + oldOwnerUuid + " \u2192 " + newOwnerUuid);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
this.logger.info('CredentialPreservationService', "\u2705 Updated " + updatedCount + " credential entries with new owner UUID");
|
|
209
|
+
};
|
|
210
|
+
/**
|
|
211
|
+
* Gets the current owner UUID from preserved credentials
|
|
212
|
+
* @returns The current owner UUID or null if not found
|
|
213
|
+
*/
|
|
214
|
+
CredentialPreservationService.prototype.getCurrentOwnerUuid = function () {
|
|
215
|
+
// Find any credential that has isOwner=true
|
|
216
|
+
for (var _i = 0, _a = Array.from(this.nodeCredentials.values()); _i < _a.length; _i++) {
|
|
217
|
+
var credentials = _a[_i];
|
|
218
|
+
if (credentials.isOwner) {
|
|
219
|
+
return credentials.ownerUuid;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
// If no owner found, return the first available ownerUuid
|
|
223
|
+
for (var _b = 0, _c = Array.from(this.nodeCredentials.values()); _b < _c.length; _b++) {
|
|
224
|
+
var credentials = _c[_b];
|
|
225
|
+
if (credentials.ownerUuid) {
|
|
226
|
+
return credentials.ownerUuid;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return null;
|
|
230
|
+
};
|
|
231
|
+
/**
|
|
232
|
+
* Validates that all credentials have consistent owner UUIDs
|
|
233
|
+
* @returns True if all credentials are consistent, false otherwise
|
|
234
|
+
*/
|
|
235
|
+
CredentialPreservationService.prototype.validateOwnerUuidConsistency = function () {
|
|
236
|
+
var ownerUuids = new Set();
|
|
237
|
+
this.nodeCredentials.forEach(function (credentials, addressStr) {
|
|
238
|
+
if (credentials.ownerUuid) {
|
|
239
|
+
ownerUuids.add(credentials.ownerUuid);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
var isConsistent = ownerUuids.size <= 1;
|
|
243
|
+
if (!isConsistent) {
|
|
244
|
+
this.logger.warn('CredentialPreservationService', "\u26A0\uFE0F Owner UUID inconsistency detected: " + Array.from(ownerUuids).join(', '));
|
|
245
|
+
}
|
|
246
|
+
return isConsistent;
|
|
247
|
+
};
|
|
248
|
+
/**
|
|
249
|
+
* Invalidates ALL credentials that have a specific owner UUID
|
|
250
|
+
* This is called when cluster membership changes and old owner UUIDs become invalid
|
|
251
|
+
* @param oldOwnerUuid The old owner UUID that is no longer valid
|
|
252
|
+
*/
|
|
253
|
+
CredentialPreservationService.prototype.invalidateCredentialsWithOwnerUuid = function (oldOwnerUuid) {
|
|
254
|
+
var _this = this;
|
|
255
|
+
this.logger.info('CredentialPreservationService', "\uD83D\uDDD1\uFE0F Invalidating ALL credentials with old owner UUID: " + oldOwnerUuid);
|
|
256
|
+
var invalidatedCount = 0;
|
|
257
|
+
var addressesToRemove = [];
|
|
258
|
+
this.nodeCredentials.forEach(function (credentials, addressStr) {
|
|
259
|
+
if (credentials.ownerUuid === oldOwnerUuid) {
|
|
260
|
+
_this.logger.info('CredentialPreservationService', "\uD83D\uDDD1\uFE0F Invalidating credentials for " + addressStr + ": old ownerUuid=" + oldOwnerUuid);
|
|
261
|
+
addressesToRemove.push(addressStr);
|
|
262
|
+
invalidatedCount++;
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
// Remove the invalidated credentials
|
|
266
|
+
addressesToRemove.forEach(function (addressStr) {
|
|
267
|
+
_this.nodeCredentials.delete(addressStr);
|
|
268
|
+
});
|
|
269
|
+
this.logger.info('CredentialPreservationService', "\u2705 Invalidated " + invalidatedCount + " credential entries with old owner UUID: " + oldOwnerUuid);
|
|
270
|
+
};
|
|
271
|
+
/**
|
|
272
|
+
* Invalidates ALL credentials that don't match the current cluster owner UUID
|
|
273
|
+
* This ensures complete credential consistency across the entire cluster
|
|
274
|
+
* @param currentClusterOwnerUuid The current cluster owner UUID that should be valid
|
|
275
|
+
*/
|
|
276
|
+
CredentialPreservationService.prototype.invalidateAllCredentialsExceptCurrentOwner = function (currentClusterOwnerUuid) {
|
|
277
|
+
var _this = this;
|
|
278
|
+
this.logger.info('CredentialPreservationService', "\uD83D\uDDD1\uFE0F Comprehensive credential cleanup: Invalidating ALL credentials except those with current owner UUID: " + currentClusterOwnerUuid);
|
|
279
|
+
var invalidatedCount = 0;
|
|
280
|
+
var addressesToRemove = [];
|
|
281
|
+
this.nodeCredentials.forEach(function (credentials, addressStr) {
|
|
282
|
+
if (credentials.ownerUuid !== currentClusterOwnerUuid) {
|
|
283
|
+
_this.logger.info('CredentialPreservationService', "\uD83D\uDDD1\uFE0F Invalidating credentials for " + addressStr + ": old ownerUuid=" + credentials.ownerUuid + " \u2260 current=" + currentClusterOwnerUuid);
|
|
284
|
+
addressesToRemove.push(addressStr);
|
|
285
|
+
invalidatedCount++;
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
_this.logger.debug('CredentialPreservationService', "\u2705 Keeping valid credentials for " + addressStr + ": ownerUuid=" + credentials.ownerUuid + " matches current");
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
// Remove the invalidated credentials
|
|
292
|
+
addressesToRemove.forEach(function (addressStr) {
|
|
293
|
+
_this.nodeCredentials.delete(addressStr);
|
|
294
|
+
});
|
|
295
|
+
this.logger.info('CredentialPreservationService', "\u2705 Comprehensive cleanup completed: Invalidated " + invalidatedCount + " credential entries, kept " + this.nodeCredentials.size + " valid entries");
|
|
296
|
+
// Log remaining valid credentials for debugging
|
|
297
|
+
if (this.nodeCredentials.size > 0) {
|
|
298
|
+
this.logger.info('CredentialPreservationService', "\uD83D\uDCCB Remaining valid credentials after cleanup:");
|
|
299
|
+
this.nodeCredentials.forEach(function (credentials, addressStr) {
|
|
300
|
+
_this.logger.info('CredentialPreservationService', " - " + addressStr + ": uuid=" + credentials.uuid + ", ownerUuid=" + credentials.ownerUuid + ", isOwner=" + credentials.isOwner);
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
/**
|
|
305
|
+
* Invalidates only problematic credentials while preserving working ones
|
|
306
|
+
* This prevents breaking working connections (like 192.168.1.108)
|
|
307
|
+
* @param currentClusterOwnerUuid The current cluster owner UUID that should be valid
|
|
308
|
+
*/
|
|
309
|
+
CredentialPreservationService.prototype.invalidateOnlyProblematicCredentials = function (currentClusterOwnerUuid) {
|
|
310
|
+
var _this = this;
|
|
311
|
+
this.logger.info('CredentialPreservationService', "\uD83C\uDFAF Targeted credential cleanup: Only invalidating problematic credentials, preserving working ones");
|
|
312
|
+
var invalidatedCount = 0;
|
|
313
|
+
var addressesToRemove = [];
|
|
314
|
+
this.nodeCredentials.forEach(function (credentials, addressStr) {
|
|
315
|
+
// Only invalidate if the ownerUuid is clearly wrong AND we've had authentication issues
|
|
316
|
+
if (credentials.ownerUuid !== currentClusterOwnerUuid) {
|
|
317
|
+
// Check if this address has had recent authentication failures
|
|
318
|
+
var hasAuthIssues = _this.hasRecentAuthenticationIssues(addressStr);
|
|
319
|
+
if (hasAuthIssues) {
|
|
320
|
+
_this.logger.info('CredentialPreservationService', "\uD83C\uDFAF Invalidating problematic credentials for " + addressStr + ": old ownerUuid=" + credentials.ownerUuid + " \u2260 current=" + currentClusterOwnerUuid + " (has auth issues)");
|
|
321
|
+
addressesToRemove.push(addressStr);
|
|
322
|
+
invalidatedCount++;
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
_this.logger.info('CredentialPreservationService', "\u2705 Keeping working credentials for " + addressStr + ": ownerUuid=" + credentials.ownerUuid + " (no auth issues)");
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
_this.logger.debug('CredentialPreservationService', "\u2705 Keeping valid credentials for " + addressStr + ": ownerUuid=" + credentials.ownerUuid + " matches current");
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
// Remove only the problematic credentials
|
|
333
|
+
addressesToRemove.forEach(function (addressStr) {
|
|
334
|
+
_this.nodeCredentials.delete(addressStr);
|
|
335
|
+
});
|
|
336
|
+
this.logger.info('CredentialPreservationService', "\u2705 Targeted cleanup completed: Invalidated " + invalidatedCount + " problematic credential entries, kept " + this.nodeCredentials.size + " working entries");
|
|
337
|
+
};
|
|
338
|
+
/**
|
|
339
|
+
* Checks if an address has had recent authentication issues
|
|
340
|
+
* This helps determine which credentials to invalidate
|
|
341
|
+
* @param addressStr The address to check
|
|
342
|
+
* @returns True if the address has recent auth issues
|
|
343
|
+
*/
|
|
344
|
+
CredentialPreservationService.prototype.hasRecentAuthenticationIssues = function (addressStr) {
|
|
345
|
+
// For now, we'll be conservative and only invalidate if we're certain
|
|
346
|
+
// In the future, we could track authentication failure history
|
|
347
|
+
return false; // Don't invalidate anything for now - revert to previous working behavior
|
|
348
|
+
};
|
|
349
|
+
/**
|
|
350
|
+
* Clears all credentials for a specific address
|
|
351
|
+
* This is called when we need to force fresh authentication for a node
|
|
352
|
+
* @param address The address to clear credentials for
|
|
353
|
+
*/
|
|
354
|
+
CredentialPreservationService.prototype.clearCredentialsForAddress = function (address) {
|
|
355
|
+
var addressStr = address.toString();
|
|
356
|
+
if (this.nodeCredentials.has(addressStr)) {
|
|
357
|
+
this.logger.info('CredentialPreservationService', "\uD83D\uDDD1\uFE0F Clearing credentials for " + addressStr);
|
|
358
|
+
this.nodeCredentials.delete(addressStr);
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
/**
|
|
362
|
+
* Gets all addresses that have credentials with a specific owner UUID
|
|
363
|
+
* @param ownerUuid The owner UUID to search for
|
|
364
|
+
* @returns Array of addresses that have credentials with this owner UUID
|
|
365
|
+
*/
|
|
366
|
+
CredentialPreservationService.prototype.getAddressesWithOwnerUuid = function (ownerUuid) {
|
|
367
|
+
var addresses = [];
|
|
368
|
+
this.nodeCredentials.forEach(function (credentials, addressStr) {
|
|
369
|
+
if (credentials.ownerUuid === ownerUuid) {
|
|
370
|
+
addresses.push(addressStr);
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
return addresses;
|
|
374
|
+
};
|
|
375
|
+
return CredentialPreservationService;
|
|
376
|
+
}());
|
|
377
|
+
exports.CredentialPreservationService = CredentialPreservationService;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { ILogger } from '../logging/ILogger';
|
|
2
|
+
import { ClientConnection } from './ClientConnection';
|
|
3
|
+
import Address = require('../Address');
|
|
4
|
+
import HazelcastClient from '../HazelcastClient';
|
|
5
|
+
/**
|
|
6
|
+
* Node state in the cluster
|
|
7
|
+
*/
|
|
8
|
+
export declare enum NodeState {
|
|
9
|
+
UNKNOWN = "unknown",
|
|
10
|
+
CONNECTING = "connecting",
|
|
11
|
+
CONNECTED = "connected",
|
|
12
|
+
OWNER = "owner",
|
|
13
|
+
CHILD = "child",
|
|
14
|
+
DISCONNECTED = "disconnected",
|
|
15
|
+
FAILED = "failed",
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Node information
|
|
19
|
+
*/
|
|
20
|
+
export interface NodeInfo {
|
|
21
|
+
address: Address;
|
|
22
|
+
state: NodeState;
|
|
23
|
+
connection: ClientConnection | null;
|
|
24
|
+
lastSeen: number;
|
|
25
|
+
failureCount: number;
|
|
26
|
+
isOwner: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Implements the Java client's failover behavior
|
|
30
|
+
* This ensures seamless node transitions and proper ownership handling
|
|
31
|
+
*/
|
|
32
|
+
export declare class HazelcastFailoverManager {
|
|
33
|
+
private readonly logger;
|
|
34
|
+
private readonly client;
|
|
35
|
+
private readonly nodes;
|
|
36
|
+
private readonly failoverInProgress;
|
|
37
|
+
private readonly failoverTimeout;
|
|
38
|
+
private currentOwner;
|
|
39
|
+
constructor(client: HazelcastClient, logger: ILogger);
|
|
40
|
+
/**
|
|
41
|
+
* Registers a node in the cluster
|
|
42
|
+
* @param address The node address
|
|
43
|
+
* @param connection The connection to the node
|
|
44
|
+
* @param isOwner Whether this node is the owner
|
|
45
|
+
*/
|
|
46
|
+
registerNode(address: Address, connection: ClientConnection, isOwner?: boolean): void;
|
|
47
|
+
/**
|
|
48
|
+
* Handles node disconnection gracefully
|
|
49
|
+
* @param address The disconnected node address
|
|
50
|
+
*/
|
|
51
|
+
handleNodeDisconnection(address: Address): void;
|
|
52
|
+
/**
|
|
53
|
+
* Handles owner node disconnection
|
|
54
|
+
* @param address The disconnected owner node address
|
|
55
|
+
*/
|
|
56
|
+
private handleOwnerDisconnection(address);
|
|
57
|
+
/**
|
|
58
|
+
* Handles child node disconnection
|
|
59
|
+
* @param address The disconnected child node address
|
|
60
|
+
*/
|
|
61
|
+
private handleChildDisconnection(address);
|
|
62
|
+
/**
|
|
63
|
+
* Selects the best candidate for new owner
|
|
64
|
+
* @returns The address of the best candidate, or null if none available
|
|
65
|
+
*/
|
|
66
|
+
private selectNewOwner();
|
|
67
|
+
/**
|
|
68
|
+
* Promotes a node to owner
|
|
69
|
+
* @param address The address of the node to promote
|
|
70
|
+
*/
|
|
71
|
+
private promoteToOwner(address);
|
|
72
|
+
/**
|
|
73
|
+
* Handles node reconnection
|
|
74
|
+
* @param address The reconnected node address
|
|
75
|
+
* @param connection The new connection
|
|
76
|
+
*/
|
|
77
|
+
handleNodeReconnection(address: Address, connection: ClientConnection): void;
|
|
78
|
+
/**
|
|
79
|
+
* Stops all failover and reconnection logic
|
|
80
|
+
*/
|
|
81
|
+
private stopFailoverLogic();
|
|
82
|
+
/**
|
|
83
|
+
* Gets the current owner address
|
|
84
|
+
* @returns The current owner address or null if no owner
|
|
85
|
+
*/
|
|
86
|
+
getCurrentOwner(): Address | null;
|
|
87
|
+
/**
|
|
88
|
+
* Gets all connected nodes
|
|
89
|
+
* @returns Array of connected node addresses
|
|
90
|
+
*/
|
|
91
|
+
getConnectedNodes(): Address[];
|
|
92
|
+
/**
|
|
93
|
+
* Gets the cluster state summary
|
|
94
|
+
* @returns Summary of cluster state
|
|
95
|
+
*/
|
|
96
|
+
getClusterStateSummary(): any;
|
|
97
|
+
/**
|
|
98
|
+
* Cleans up failed nodes that haven't recovered
|
|
99
|
+
* @param maxFailureAge Maximum age for failed nodes (default: 5 minutes)
|
|
100
|
+
*/
|
|
101
|
+
cleanupFailedNodes(maxFailureAge?: number): void;
|
|
102
|
+
}
|