kuzzle 2.20.2 → 2.21.0
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/api/controllers/debugController.d.ts +2 -27
- package/lib/api/controllers/debugController.js +8 -182
- package/lib/api/controllers/documentController.js +122 -10
- package/lib/api/request/kuzzleRequest.d.ts +8 -0
- package/lib/api/request/kuzzleRequest.js +12 -0
- package/lib/cluster/idCardHandler.js +19 -6
- package/lib/cluster/node.js +18 -1
- package/lib/cluster/protobuf/sync.proto +5 -0
- package/lib/cluster/publisher.js +10 -0
- package/lib/cluster/subscriber.js +8 -1
- package/lib/cluster/workers/IDCardRenewer.js +23 -26
- package/lib/config/default.config.js +1 -0
- package/lib/core/debug/kuzzleDebugger.d.ts +45 -0
- package/lib/core/debug/kuzzleDebugger.js +205 -0
- package/lib/core/storage/clientAdapter.js +4 -2
- package/lib/kuzzle/dumpGenerator.js +1 -1
- package/lib/kuzzle/kuzzle.js +3 -0
- package/lib/service/storage/elasticsearch.js +46 -36
- package/lib/types/config/storageEngine/StorageEngineElasticsearchConfiguration.d.ts +15 -3
- package/lib/types/events/EventGenericDocument.d.ts +21 -1
- package/package.json +1 -1
- package/lib/types/DebugModule.d.ts +0 -24
- package/lib/types/DebugModule.js +0 -39
|
@@ -4,23 +4,10 @@ import { NativeController } from "./baseController";
|
|
|
4
4
|
* @class DebugController
|
|
5
5
|
*/
|
|
6
6
|
export declare class DebugController extends NativeController {
|
|
7
|
-
|
|
8
|
-
private debuggerStatus;
|
|
9
|
-
/**
|
|
10
|
-
* Map<eventName, Set<connectionId>>
|
|
11
|
-
*/
|
|
12
|
-
private events;
|
|
13
|
-
/**
|
|
14
|
-
* Map of functions from the DebugModules
|
|
15
|
-
*/
|
|
16
|
-
private kuzzlePostMethods;
|
|
7
|
+
constructor();
|
|
17
8
|
/**
|
|
18
|
-
*
|
|
19
|
-
* Used to add new methods and events to the protocol
|
|
9
|
+
* Return the node version of the current Kuzzle instance
|
|
20
10
|
*/
|
|
21
|
-
private modules;
|
|
22
|
-
constructor();
|
|
23
|
-
init(): Promise<void>;
|
|
24
11
|
nodeVersion(): Promise<string>;
|
|
25
12
|
/**
|
|
26
13
|
* Connect the debugger
|
|
@@ -44,16 +31,4 @@ export declare class DebugController extends NativeController {
|
|
|
44
31
|
* Remove the websocket connection from the events' listeners
|
|
45
32
|
*/
|
|
46
33
|
removeListener(request: KuzzleRequest): Promise<void>;
|
|
47
|
-
/**
|
|
48
|
-
* Execute a method using the Chrome Debug Protocol
|
|
49
|
-
* @param method Chrome Debug Protocol method to execute
|
|
50
|
-
* @param params
|
|
51
|
-
* @returns
|
|
52
|
-
*/
|
|
53
|
-
private inspectorPost;
|
|
54
|
-
/**
|
|
55
|
-
* Sends a direct notification to a websocket connection without having to listen to a specific room
|
|
56
|
-
*/
|
|
57
|
-
private notifyConnection;
|
|
58
|
-
private notifyGlobalListeners;
|
|
59
34
|
}
|
|
@@ -42,16 +42,10 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
42
42
|
__setModuleDefault(result, mod);
|
|
43
43
|
return result;
|
|
44
44
|
};
|
|
45
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
46
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
47
|
-
};
|
|
48
45
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
49
46
|
exports.DebugController = void 0;
|
|
50
47
|
const baseController_1 = require("./baseController");
|
|
51
|
-
const inspector_1 = __importDefault(require("inspector"));
|
|
52
48
|
const kerror = __importStar(require("../../kerror"));
|
|
53
|
-
const get_1 = __importDefault(require("lodash/get"));
|
|
54
|
-
const DEBUGGER_EVENT = "kuzzle-debugger-event";
|
|
55
49
|
/**
|
|
56
50
|
* @class DebugController
|
|
57
51
|
*/
|
|
@@ -65,53 +59,10 @@ class DebugController extends baseController_1.NativeController {
|
|
|
65
59
|
"addListener",
|
|
66
60
|
"removeListener",
|
|
67
61
|
]);
|
|
68
|
-
this.debuggerStatus = false;
|
|
69
|
-
/**
|
|
70
|
-
* Map<eventName, Set<connectionId>>
|
|
71
|
-
*/
|
|
72
|
-
this.events = new Map();
|
|
73
|
-
/**
|
|
74
|
-
* Map of functions from the DebugModules
|
|
75
|
-
*/
|
|
76
|
-
this.kuzzlePostMethods = new Map();
|
|
77
|
-
/**
|
|
78
|
-
* List of DebugModule for DebugController
|
|
79
|
-
* Used to add new methods and events to the protocol
|
|
80
|
-
*/
|
|
81
|
-
this.modules = [];
|
|
82
|
-
}
|
|
83
|
-
async init() {
|
|
84
|
-
super.init();
|
|
85
|
-
this.inspector = new inspector_1.default.Session();
|
|
86
|
-
// Remove connection id from the list of listeners for each event
|
|
87
|
-
global.kuzzle.on("connection:remove", (connectionId) => {
|
|
88
|
-
if (!this.debuggerStatus) {
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
for (const listener of this.events.values()) {
|
|
92
|
-
listener.delete(connectionId);
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
this.inspector.on("inspectorNotification", async (payload) => {
|
|
96
|
-
if (!this.debuggerStatus) {
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
await this.notifyGlobalListeners(payload.method, payload);
|
|
100
|
-
const listeners = this.events.get(payload.method);
|
|
101
|
-
if (!listeners) {
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
const promises = [];
|
|
105
|
-
for (const connectionId of listeners) {
|
|
106
|
-
promises.push(this.notifyConnection(connectionId, DEBUGGER_EVENT, {
|
|
107
|
-
event: payload.method,
|
|
108
|
-
result: payload,
|
|
109
|
-
}));
|
|
110
|
-
}
|
|
111
|
-
// No need to catch, notify is already try-catched
|
|
112
|
-
await Promise.all(promises);
|
|
113
|
-
});
|
|
114
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Return the node version of the current Kuzzle instance
|
|
65
|
+
*/
|
|
115
66
|
async nodeVersion() {
|
|
116
67
|
return process.version;
|
|
117
68
|
}
|
|
@@ -119,82 +70,22 @@ class DebugController extends baseController_1.NativeController {
|
|
|
119
70
|
* Connect the debugger
|
|
120
71
|
*/
|
|
121
72
|
async enable() {
|
|
122
|
-
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
this.inspector.connect();
|
|
126
|
-
this.debuggerStatus = true;
|
|
127
|
-
for (const module of this.modules) {
|
|
128
|
-
await module.init(this.inspector);
|
|
129
|
-
for (const methodName of module.methods) {
|
|
130
|
-
if (!module[methodName]) {
|
|
131
|
-
throw new Error(`Missing implementation of method "${methodName}" inside DebugModule "${module.name}"`);
|
|
132
|
-
}
|
|
133
|
-
this.kuzzlePostMethods.set(`Kuzzle.${module.name}.${methodName}`, module[methodName].bind(module));
|
|
134
|
-
}
|
|
135
|
-
for (const eventName of module.events) {
|
|
136
|
-
module.on(eventName, async (payload) => {
|
|
137
|
-
if (!this.debuggerStatus) {
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
const event = `Kuzzle.${module.name}.${eventName}`;
|
|
141
|
-
await this.notifyGlobalListeners(event, payload);
|
|
142
|
-
const listeners = this.events.get(event);
|
|
143
|
-
if (!listeners) {
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
const promises = [];
|
|
147
|
-
for (const connectionId of listeners) {
|
|
148
|
-
promises.push(this.notifyConnection(connectionId, DEBUGGER_EVENT, {
|
|
149
|
-
event,
|
|
150
|
-
result: payload,
|
|
151
|
-
}));
|
|
152
|
-
}
|
|
153
|
-
// No need to catch, notify is already try-catched
|
|
154
|
-
await Promise.all(promises);
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
}
|
|
73
|
+
await global.kuzzle.ask("core:debugger:enable");
|
|
158
74
|
}
|
|
159
75
|
/**
|
|
160
76
|
* Disconnect the debugger and clears all the events listeners
|
|
161
77
|
*/
|
|
162
78
|
async disable() {
|
|
163
|
-
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
for (const module of this.modules) {
|
|
167
|
-
for (const eventName of module.events) {
|
|
168
|
-
module.removeAllListeners(eventName);
|
|
169
|
-
}
|
|
170
|
-
await module.cleanup();
|
|
171
|
-
}
|
|
172
|
-
this.inspector.disconnect();
|
|
173
|
-
this.debuggerStatus = false;
|
|
174
|
-
this.events.clear();
|
|
175
|
-
this.kuzzlePostMethods.clear();
|
|
79
|
+
await global.kuzzle.ask("core:debugger:disable");
|
|
176
80
|
}
|
|
177
81
|
/**
|
|
178
82
|
* Trigger action from debugger directly following the Chrome Debug Protocol
|
|
179
83
|
* See: https://chromedevtools.github.io/devtools-protocol/v8/
|
|
180
84
|
*/
|
|
181
85
|
async post(request) {
|
|
182
|
-
if (!this.debuggerStatus) {
|
|
183
|
-
throw kerror.get("core", "debugger", "not_enabled");
|
|
184
|
-
}
|
|
185
86
|
const method = request.getBodyString("method");
|
|
186
87
|
const params = request.getBodyObject("params", {});
|
|
187
|
-
|
|
188
|
-
const debugModuleMethod = this.kuzzlePostMethods.get(method);
|
|
189
|
-
if (debugModuleMethod) {
|
|
190
|
-
return debugModuleMethod(params);
|
|
191
|
-
}
|
|
192
|
-
throw kerror.get("core", "debugger", "method_not_found", method);
|
|
193
|
-
}
|
|
194
|
-
if (!(0, get_1.default)(global.kuzzle.config, "security.debug.native_debug_protocol")) {
|
|
195
|
-
throw kerror.get("core", "debugger", "native_debug_protocol_usage_denied");
|
|
196
|
-
}
|
|
197
|
-
return this.inspectorPost(method, params);
|
|
88
|
+
return global.kuzzle.ask("core:debugger:post", method, params);
|
|
198
89
|
}
|
|
199
90
|
/**
|
|
200
91
|
* Make the websocket connection listen and receive events from Chrome Debug Protocol
|
|
@@ -204,16 +95,8 @@ class DebugController extends baseController_1.NativeController {
|
|
|
204
95
|
if (request.context.connection.protocol !== "websocket") {
|
|
205
96
|
throw kerror.get("api", "assert", "unsupported_protocol", request.context.connection.protocol, "debug:addListener");
|
|
206
97
|
}
|
|
207
|
-
if (!this.debuggerStatus) {
|
|
208
|
-
throw kerror.get("core", "debugger", "not_enabled");
|
|
209
|
-
}
|
|
210
98
|
const event = request.getBodyString("event");
|
|
211
|
-
|
|
212
|
-
if (!listeners) {
|
|
213
|
-
listeners = new Set();
|
|
214
|
-
this.events.set(event, listeners);
|
|
215
|
-
}
|
|
216
|
-
listeners.add(request.context.connection.id);
|
|
99
|
+
await global.kuzzle.ask("core:debugger:addListener", event, request.context.connection.id);
|
|
217
100
|
}
|
|
218
101
|
/**
|
|
219
102
|
* Remove the websocket connection from the events' listeners
|
|
@@ -222,65 +105,8 @@ class DebugController extends baseController_1.NativeController {
|
|
|
222
105
|
if (request.context.connection.protocol !== "websocket") {
|
|
223
106
|
throw kerror.get("api", "assert", "unsupported_protocol", request.context.connection.protocol, "debug:removeListener");
|
|
224
107
|
}
|
|
225
|
-
if (!this.debuggerStatus) {
|
|
226
|
-
throw kerror.get("core", "debugger", "not_enabled");
|
|
227
|
-
}
|
|
228
108
|
const event = request.getBodyString("event");
|
|
229
|
-
|
|
230
|
-
if (listeners) {
|
|
231
|
-
listeners.delete(request.context.connection.id);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
/**
|
|
235
|
-
* Execute a method using the Chrome Debug Protocol
|
|
236
|
-
* @param method Chrome Debug Protocol method to execute
|
|
237
|
-
* @param params
|
|
238
|
-
* @returns
|
|
239
|
-
*/
|
|
240
|
-
async inspectorPost(method, params) {
|
|
241
|
-
if (!this.debuggerStatus) {
|
|
242
|
-
throw kerror.get("core", "debugger", "not_enabled");
|
|
243
|
-
}
|
|
244
|
-
let resolve;
|
|
245
|
-
const promise = new Promise((res) => {
|
|
246
|
-
resolve = res;
|
|
247
|
-
});
|
|
248
|
-
this.inspector.post(method, params, (err, res) => {
|
|
249
|
-
if (err) {
|
|
250
|
-
resolve({
|
|
251
|
-
error: JSON.stringify(Object.getOwnPropertyDescriptors(err)),
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
else {
|
|
255
|
-
resolve(res);
|
|
256
|
-
}
|
|
257
|
-
});
|
|
258
|
-
return promise;
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Sends a direct notification to a websocket connection without having to listen to a specific room
|
|
262
|
-
*/
|
|
263
|
-
async notifyConnection(connectionId, event, payload) {
|
|
264
|
-
global.kuzzle.entryPoint._notify({
|
|
265
|
-
channels: [event],
|
|
266
|
-
connectionId,
|
|
267
|
-
payload,
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
async notifyGlobalListeners(event, payload) {
|
|
271
|
-
const listeners = this.events.get("*");
|
|
272
|
-
if (!listeners) {
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
const promises = [];
|
|
276
|
-
for (const connectionId of listeners) {
|
|
277
|
-
promises.push(this.notifyConnection(connectionId, DEBUGGER_EVENT, {
|
|
278
|
-
event,
|
|
279
|
-
result: payload,
|
|
280
|
-
}));
|
|
281
|
-
}
|
|
282
|
-
// No need to catch, notify is already try-catched
|
|
283
|
-
await Promise.all(promises);
|
|
109
|
+
await global.kuzzle.ask("core:debugger:removeListener", event, request.context.connection.id);
|
|
284
110
|
}
|
|
285
111
|
}
|
|
286
112
|
exports.DebugController = DebugController;
|
|
@@ -390,12 +390,34 @@ class DocumentController extends NativeController {
|
|
|
390
390
|
|
|
391
391
|
const validated = await global.kuzzle.validation.validate(request, false);
|
|
392
392
|
|
|
393
|
+
// Add metadata
|
|
394
|
+
const pipeMetadataResult = await this.pipe(
|
|
395
|
+
"generic:document:injectMetadata",
|
|
396
|
+
{
|
|
397
|
+
metadata: {
|
|
398
|
+
author: userId,
|
|
399
|
+
createdAt: Date.now(),
|
|
400
|
+
updatedAt: null,
|
|
401
|
+
updater: null,
|
|
402
|
+
},
|
|
403
|
+
request,
|
|
404
|
+
}
|
|
405
|
+
);
|
|
406
|
+
|
|
393
407
|
const created = await this.ask(
|
|
394
408
|
"core:storage:public:document:create",
|
|
395
409
|
index,
|
|
396
410
|
collection,
|
|
397
|
-
|
|
398
|
-
|
|
411
|
+
{
|
|
412
|
+
...validated.getBody(),
|
|
413
|
+
_kuzzle_info: pipeMetadataResult.metadata,
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
id,
|
|
417
|
+
injectKuzzleMeta: false,
|
|
418
|
+
refresh,
|
|
419
|
+
userId,
|
|
420
|
+
}
|
|
399
421
|
);
|
|
400
422
|
|
|
401
423
|
if (!silent) {
|
|
@@ -440,13 +462,34 @@ class DocumentController extends NativeController {
|
|
|
440
462
|
false
|
|
441
463
|
);
|
|
442
464
|
|
|
465
|
+
// Add metadata
|
|
466
|
+
const pipeMetadataResult = await this.pipe(
|
|
467
|
+
"generic:document:injectMetadata",
|
|
468
|
+
{
|
|
469
|
+
metadata: {
|
|
470
|
+
author: userId,
|
|
471
|
+
createdAt: Date.now(),
|
|
472
|
+
updatedAt: Date.now(),
|
|
473
|
+
updater: userId,
|
|
474
|
+
},
|
|
475
|
+
request,
|
|
476
|
+
}
|
|
477
|
+
);
|
|
478
|
+
|
|
443
479
|
const response = await this.ask(
|
|
444
480
|
"core:storage:public:document:createOrReplace",
|
|
445
481
|
index,
|
|
446
482
|
collection,
|
|
447
483
|
id,
|
|
448
|
-
|
|
449
|
-
|
|
484
|
+
{
|
|
485
|
+
...content,
|
|
486
|
+
_kuzzle_info: pipeMetadataResult.metadata,
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
injectKuzzleMeta: false,
|
|
490
|
+
refresh,
|
|
491
|
+
userId,
|
|
492
|
+
}
|
|
450
493
|
);
|
|
451
494
|
|
|
452
495
|
if (!silent) {
|
|
@@ -493,13 +536,33 @@ class DocumentController extends NativeController {
|
|
|
493
536
|
false
|
|
494
537
|
);
|
|
495
538
|
|
|
539
|
+
// Add metadata
|
|
540
|
+
const pipeMetadataResult = await this.pipe(
|
|
541
|
+
"generic:document:injectMetadata",
|
|
542
|
+
{
|
|
543
|
+
metadata: {
|
|
544
|
+
updatedAt: Date.now(),
|
|
545
|
+
updater: userId,
|
|
546
|
+
},
|
|
547
|
+
request,
|
|
548
|
+
}
|
|
549
|
+
);
|
|
550
|
+
|
|
496
551
|
const updatedDocument = await this.ask(
|
|
497
552
|
"core:storage:public:document:update",
|
|
498
553
|
index,
|
|
499
554
|
collection,
|
|
500
555
|
id,
|
|
501
|
-
|
|
502
|
-
|
|
556
|
+
{
|
|
557
|
+
...content,
|
|
558
|
+
_kuzzle_info: pipeMetadataResult.metadata,
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
injectKuzzleMeta: false,
|
|
562
|
+
refresh,
|
|
563
|
+
retryOnConflict,
|
|
564
|
+
userId,
|
|
565
|
+
}
|
|
503
566
|
);
|
|
504
567
|
|
|
505
568
|
const _updatedFields = extractFields(content, {
|
|
@@ -548,13 +611,41 @@ class DocumentController extends NativeController {
|
|
|
548
611
|
const source = request.getBoolean("source");
|
|
549
612
|
const { index, collection } = request.getIndexAndCollection();
|
|
550
613
|
|
|
614
|
+
// Add metadata
|
|
615
|
+
const pipeMetadataResult = await this.pipe(
|
|
616
|
+
"generic:document:injectMetadata",
|
|
617
|
+
{
|
|
618
|
+
defaultMetadata: {
|
|
619
|
+
author: userId,
|
|
620
|
+
createdAt: Date.now(),
|
|
621
|
+
},
|
|
622
|
+
metadata: {
|
|
623
|
+
updatedAt: Date.now(),
|
|
624
|
+
updater: userId,
|
|
625
|
+
},
|
|
626
|
+
request,
|
|
627
|
+
}
|
|
628
|
+
);
|
|
629
|
+
|
|
551
630
|
const updatedDocument = await this.ask(
|
|
552
631
|
"core:storage:public:document:upsert",
|
|
553
632
|
index,
|
|
554
633
|
collection,
|
|
555
634
|
id,
|
|
556
|
-
|
|
557
|
-
|
|
635
|
+
{
|
|
636
|
+
...content,
|
|
637
|
+
_kuzzle_info: pipeMetadataResult.metadata,
|
|
638
|
+
},
|
|
639
|
+
{
|
|
640
|
+
defaultValues: {
|
|
641
|
+
...defaultValues,
|
|
642
|
+
_kuzzle_info: pipeMetadataResult.defaultMetadata,
|
|
643
|
+
},
|
|
644
|
+
injectKuzzleMeta: false,
|
|
645
|
+
refresh,
|
|
646
|
+
retryOnConflict,
|
|
647
|
+
userId,
|
|
648
|
+
}
|
|
558
649
|
);
|
|
559
650
|
|
|
560
651
|
if (!silent && updatedDocument.created) {
|
|
@@ -633,13 +724,34 @@ class DocumentController extends NativeController {
|
|
|
633
724
|
false
|
|
634
725
|
);
|
|
635
726
|
|
|
727
|
+
// Add metadata
|
|
728
|
+
const pipeMetadataResult = await this.pipe(
|
|
729
|
+
"generic:document:injectMetadata",
|
|
730
|
+
{
|
|
731
|
+
metadata: {
|
|
732
|
+
author: userId,
|
|
733
|
+
createdAt: Date.now(),
|
|
734
|
+
updatedAt: Date.now(),
|
|
735
|
+
updater: userId,
|
|
736
|
+
},
|
|
737
|
+
request,
|
|
738
|
+
}
|
|
739
|
+
);
|
|
740
|
+
|
|
636
741
|
const response = await this.ask(
|
|
637
742
|
"core:storage:public:document:replace",
|
|
638
743
|
index,
|
|
639
744
|
collection,
|
|
640
745
|
id,
|
|
641
|
-
|
|
642
|
-
|
|
746
|
+
{
|
|
747
|
+
...content,
|
|
748
|
+
_kuzzle_info: pipeMetadataResult.metadata,
|
|
749
|
+
},
|
|
750
|
+
{
|
|
751
|
+
injectKuzzleMeta: false,
|
|
752
|
+
refresh,
|
|
753
|
+
userId,
|
|
754
|
+
}
|
|
643
755
|
);
|
|
644
756
|
|
|
645
757
|
if (!silent) {
|
|
@@ -135,6 +135,14 @@ export declare class KuzzleRequest {
|
|
|
135
135
|
status: number;
|
|
136
136
|
timestamp: number;
|
|
137
137
|
};
|
|
138
|
+
/**
|
|
139
|
+
* Return the requested controller
|
|
140
|
+
*/
|
|
141
|
+
getController(): string;
|
|
142
|
+
/**
|
|
143
|
+
* Returns the requested controller's action
|
|
144
|
+
*/
|
|
145
|
+
getAction(): string;
|
|
138
146
|
/**
|
|
139
147
|
* Returns the `lang` param of the request.
|
|
140
148
|
*
|
|
@@ -324,6 +324,18 @@ class KuzzleRequest {
|
|
|
324
324
|
timestamp: this.timestamp,
|
|
325
325
|
};
|
|
326
326
|
}
|
|
327
|
+
/**
|
|
328
|
+
* Return the requested controller
|
|
329
|
+
*/
|
|
330
|
+
getController() {
|
|
331
|
+
return this[_input].controller;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Returns the requested controller's action
|
|
335
|
+
*/
|
|
336
|
+
getAction() {
|
|
337
|
+
return this[_input].action;
|
|
338
|
+
}
|
|
327
339
|
/**
|
|
328
340
|
* Returns the `lang` param of the request.
|
|
329
341
|
*
|
|
@@ -25,7 +25,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.ClusterIdCardHandler = exports.IdCard = void 0;
|
|
27
27
|
const name_generator_1 = require("../util/name-generator");
|
|
28
|
-
const
|
|
28
|
+
const child_process_1 = require("child_process");
|
|
29
29
|
const bluebird_1 = __importDefault(require("bluebird"));
|
|
30
30
|
require("../types");
|
|
31
31
|
const REDIS_PREFIX = "{cluster/node}/";
|
|
@@ -110,14 +110,16 @@ class ClusterIdCardHandler {
|
|
|
110
110
|
} while (!reserved);
|
|
111
111
|
await this.addIdCardToIndex();
|
|
112
112
|
this.refreshWorker = this.constructWorker(`${__dirname}/workers/IDCardRenewer.js`);
|
|
113
|
-
this.refreshWorker.unref();
|
|
114
113
|
this.refreshWorker.on("message", async (message) => {
|
|
115
114
|
if (message.error) {
|
|
116
115
|
await this.node.evictSelf(message.error);
|
|
117
116
|
}
|
|
118
117
|
});
|
|
118
|
+
this.refreshWorker.on("close", () => {
|
|
119
|
+
this.disposed = true;
|
|
120
|
+
});
|
|
119
121
|
// Transfer informations to the worker
|
|
120
|
-
this.refreshWorker.
|
|
122
|
+
this.refreshWorker.send({
|
|
121
123
|
action: "start",
|
|
122
124
|
kuzzle: {
|
|
123
125
|
config: global.kuzzle.config,
|
|
@@ -138,7 +140,7 @@ class ClusterIdCardHandler {
|
|
|
138
140
|
* Helper method to mock worker instantiation in unit tests
|
|
139
141
|
*/
|
|
140
142
|
constructWorker(path) {
|
|
141
|
-
return
|
|
143
|
+
return (0, child_process_1.fork)(path);
|
|
142
144
|
}
|
|
143
145
|
/**
|
|
144
146
|
* Start refreshing the ID Card before the worker starts to ensure the ID Card
|
|
@@ -163,9 +165,20 @@ class ClusterIdCardHandler {
|
|
|
163
165
|
});
|
|
164
166
|
}
|
|
165
167
|
async dispose() {
|
|
168
|
+
if (this.disposed) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
166
171
|
this.disposed = true;
|
|
167
|
-
if (this.refreshWorker
|
|
168
|
-
this.refreshWorker.
|
|
172
|
+
if (this.refreshWorker &&
|
|
173
|
+
this.refreshWorker.connected &&
|
|
174
|
+
!this.refreshWorker.killed &&
|
|
175
|
+
this.refreshWorker.channel) {
|
|
176
|
+
try {
|
|
177
|
+
this.refreshWorker.send({ action: "dispose" });
|
|
178
|
+
}
|
|
179
|
+
catch (e) {
|
|
180
|
+
// It could happens that the worker has been killed before the dispose causing send to fail
|
|
181
|
+
}
|
|
169
182
|
}
|
|
170
183
|
}
|
|
171
184
|
/**
|
package/lib/cluster/node.js
CHANGED
|
@@ -249,6 +249,15 @@ class ClusterNode {
|
|
|
249
249
|
this.command.dispose();
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
+
/**
|
|
253
|
+
* Notify other nodes to not evict this node
|
|
254
|
+
*
|
|
255
|
+
* @param {bool} evictionPrevented
|
|
256
|
+
*/
|
|
257
|
+
preventEviction(evictionPrevented) {
|
|
258
|
+
this.publisher.sendNodePreventEviction(evictionPrevented);
|
|
259
|
+
}
|
|
260
|
+
|
|
252
261
|
/**
|
|
253
262
|
* Adds a new remote node, and subscribes to it.
|
|
254
263
|
* @param {string} id - remote node ID
|
|
@@ -678,6 +687,10 @@ class ClusterNode {
|
|
|
678
687
|
* Registers ask events
|
|
679
688
|
*/
|
|
680
689
|
registerAskEvents() {
|
|
690
|
+
global.kuzzle.onAsk("cluster:node:preventEviction", (state) => {
|
|
691
|
+
this.preventEviction(state);
|
|
692
|
+
});
|
|
693
|
+
|
|
681
694
|
/**
|
|
682
695
|
* Removes a room from the full state, and only for this node.
|
|
683
696
|
* Removes the room from Koncorde if, and only if, no other node uses it.
|
|
@@ -816,7 +829,11 @@ class ClusterNode {
|
|
|
816
829
|
this.onAuthStrategyRemoved(name, pluginName)
|
|
817
830
|
);
|
|
818
831
|
|
|
819
|
-
global.kuzzle.on("admin:afterDump", (
|
|
832
|
+
global.kuzzle.on("admin:afterDump", (request) => {
|
|
833
|
+
const suffix = request.getString("suffix", "manual-api-action");
|
|
834
|
+
|
|
835
|
+
return this.onDumpRequest(suffix);
|
|
836
|
+
});
|
|
820
837
|
|
|
821
838
|
global.kuzzle.on("admin:afterResetSecurity", () => this.onSecurityReset());
|
|
822
839
|
|
package/lib/cluster/publisher.js
CHANGED
|
@@ -270,6 +270,16 @@ class ClusterPublisher {
|
|
|
270
270
|
return this.send("NodeShutdown", { nodeId });
|
|
271
271
|
}
|
|
272
272
|
|
|
273
|
+
/**
|
|
274
|
+
* Publishes an event about the node being in debug mode
|
|
275
|
+
* @param {bool} evictionPrevented
|
|
276
|
+
*
|
|
277
|
+
* @returns {Long} ID of the message sent
|
|
278
|
+
*/
|
|
279
|
+
sendNodePreventEviction(evictionPrevented) {
|
|
280
|
+
return this.send("NodePreventEviction", { evictionPrevented });
|
|
281
|
+
}
|
|
282
|
+
|
|
273
283
|
/**
|
|
274
284
|
* Publishes an event about a node being evicted
|
|
275
285
|
*
|
|
@@ -55,6 +55,8 @@ class ClusterSubscriber {
|
|
|
55
55
|
this.remoteNodeIP = remoteNodeIP;
|
|
56
56
|
this.remoteNodeAddress = `tcp://${remoteNodeIP}:${this.localNode.config.ports.sync}`;
|
|
57
57
|
this.remoteNodeId = remoteNodeId;
|
|
58
|
+
// Used in debug mode when the node might be slower
|
|
59
|
+
this.remoteNodeEvictionPrevented = false;
|
|
58
60
|
this.socket = null;
|
|
59
61
|
this.protoroot = null;
|
|
60
62
|
|
|
@@ -87,6 +89,7 @@ class ClusterSubscriber {
|
|
|
87
89
|
NewAuthStrategy: this.handleNewAuthStrategy,
|
|
88
90
|
NewRealtimeRoom: this.handleNewRealtimeRoom,
|
|
89
91
|
NodeEvicted: this.handleNodeEviction,
|
|
92
|
+
NodePreventEviction: this.handleNodePreventEviction,
|
|
90
93
|
NodeShutdown: this.handleNodeShutdown,
|
|
91
94
|
RefreshIndexCache: this.handleRefreshIndexCache,
|
|
92
95
|
RefreshValidators: this.handleRefreshValidators,
|
|
@@ -229,6 +232,10 @@ class ClusterSubscriber {
|
|
|
229
232
|
}
|
|
230
233
|
}
|
|
231
234
|
|
|
235
|
+
async handleNodePreventEviction(message) {
|
|
236
|
+
this.remoteNodeEvictionPrevented = message.evictionPrevented;
|
|
237
|
+
}
|
|
238
|
+
|
|
232
239
|
/**
|
|
233
240
|
* Handles a heartbeat from the remote node
|
|
234
241
|
*
|
|
@@ -673,7 +680,7 @@ class ClusterSubscriber {
|
|
|
673
680
|
* to recover, otherwise we evict it from the cluster.
|
|
674
681
|
*/
|
|
675
682
|
async checkHeartbeat() {
|
|
676
|
-
if (this.state === stateEnum.EVICTED) {
|
|
683
|
+
if (this.state === stateEnum.EVICTED || this.remoteNodeEvictionPrevented) {
|
|
677
684
|
return;
|
|
678
685
|
}
|
|
679
686
|
|