kuzzle 2.14.16 → 2.16.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/adminController.js +5 -0
- package/lib/api/controllers/documentController.js +1 -5
- package/lib/api/controllers/serverController.js +24 -4
- package/lib/api/funnel.js +19 -0
- package/lib/{config → api}/httpRoutes.js +30 -14
- package/lib/api/openApiGenerator.d.ts +6 -0
- package/lib/api/openApiGenerator.js +167 -126
- package/lib/api/openapi/documents/document.d.ts +21 -0
- package/lib/api/openapi/documents/document.js +57 -0
- package/lib/api/openapi/tools.d.ts +2 -0
- package/lib/api/openapi/tools.js +10 -0
- package/lib/api/request/kuzzleRequest.d.ts +30 -32
- package/lib/api/request/kuzzleRequest.js +30 -102
- package/lib/api/request/requestContext.d.ts +17 -22
- package/lib/api/request/requestContext.js +44 -109
- package/lib/api/request/requestInput.d.ts +19 -22
- package/lib/api/request/requestInput.js +115 -173
- package/lib/api/request/requestResponse.d.ts +12 -8
- package/lib/api/request/requestResponse.js +35 -29
- package/lib/cluster/idCardHandler.d.ts +140 -0
- package/lib/cluster/idCardHandler.js +218 -214
- package/lib/cluster/node.js +11 -0
- package/lib/cluster/protobuf/sync.proto +4 -0
- package/lib/cluster/subscriber.js +9 -12
- package/lib/cluster/workers/IDCardRenewer.js +13 -7
- package/lib/config/default.config.js +1 -1
- package/lib/core/network/router.js +33 -0
- package/lib/core/plugin/pluginsManager.js +3 -1
- package/lib/core/realtime/hotelClerk.d.ts +7 -0
- package/lib/core/realtime/hotelClerk.js +14 -0
- package/lib/core/realtime/notifier.js +16 -18
- package/lib/core/storage/clientAdapter.js +11 -5
- package/lib/core/storage/indexCache.d.ts +55 -0
- package/lib/core/storage/indexCache.js +97 -130
- package/lib/kuzzle/kuzzle.js +11 -7
- package/lib/service/storage/elasticsearch.js +14 -9
- package/package-lock.json +286 -260
- package/package.json +18 -17
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import '../types';
|
|
2
|
+
export declare type SerializedIdCard = {
|
|
3
|
+
id: string;
|
|
4
|
+
ip: string;
|
|
5
|
+
birthdate: number;
|
|
6
|
+
topology: string[];
|
|
7
|
+
};
|
|
8
|
+
export declare class IdCard {
|
|
9
|
+
/**
|
|
10
|
+
* Node unique identifier
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
*
|
|
14
|
+
* knode-pensive-einstein-844221
|
|
15
|
+
*/
|
|
16
|
+
private id;
|
|
17
|
+
/**
|
|
18
|
+
* Node IP address
|
|
19
|
+
*/
|
|
20
|
+
private ip;
|
|
21
|
+
/**
|
|
22
|
+
* Node creation timestamp
|
|
23
|
+
*/
|
|
24
|
+
private birthdate;
|
|
25
|
+
/**
|
|
26
|
+
* Node known topology composed of node IDs
|
|
27
|
+
*
|
|
28
|
+
* Set<node-id>
|
|
29
|
+
*/
|
|
30
|
+
topology: Set<string>;
|
|
31
|
+
constructor({ id, ip, birthdate, topology }: SerializedIdCard);
|
|
32
|
+
serialize(): SerializedIdCard;
|
|
33
|
+
static unserialize(serialized: SerializedIdCard): IdCard;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Handles the ID Key stored in Redis, holding node information
|
|
37
|
+
*/
|
|
38
|
+
export declare class ClusterIdCardHandler {
|
|
39
|
+
/**
|
|
40
|
+
* Node instance. Represents the local node.
|
|
41
|
+
*/
|
|
42
|
+
private node;
|
|
43
|
+
/**
|
|
44
|
+
* Local node ID Card
|
|
45
|
+
*/
|
|
46
|
+
private idCard;
|
|
47
|
+
/**
|
|
48
|
+
* Local node IP address
|
|
49
|
+
*/
|
|
50
|
+
private ip;
|
|
51
|
+
/**
|
|
52
|
+
* Delay for refreshing the ID Card. The heartbeat timer is run on this delay
|
|
53
|
+
* and the node ID Card should be available on Redis otherwise it will be evicted.
|
|
54
|
+
*/
|
|
55
|
+
private refreshDelay;
|
|
56
|
+
/**
|
|
57
|
+
* Multiplier used to ensure the node has enough time to refresh it's ID Card
|
|
58
|
+
* before the ID Card refresh delay
|
|
59
|
+
*/
|
|
60
|
+
private refreshMultiplier;
|
|
61
|
+
/**
|
|
62
|
+
* Worker thread in charge of refreshing the ID Card once the node has started
|
|
63
|
+
*/
|
|
64
|
+
private refreshWorker;
|
|
65
|
+
/**
|
|
66
|
+
* Hold the timer in charge of refreshing the ID Card before the worker starts
|
|
67
|
+
*/
|
|
68
|
+
private refreshTimer;
|
|
69
|
+
/**
|
|
70
|
+
* Local node ID
|
|
71
|
+
*/
|
|
72
|
+
private nodeId;
|
|
73
|
+
/**
|
|
74
|
+
* Local node Redis key
|
|
75
|
+
*/
|
|
76
|
+
private nodeIdKey;
|
|
77
|
+
/**
|
|
78
|
+
* Flag to prevent updating the id card if it has been disposed.
|
|
79
|
+
* Prevents race condition if a topology update occurs at the same time as
|
|
80
|
+
* the id card is been disposed because the node is evicting itself from the
|
|
81
|
+
* cluster
|
|
82
|
+
*/
|
|
83
|
+
private disposed;
|
|
84
|
+
constructor(node: any);
|
|
85
|
+
/**
|
|
86
|
+
* Generates and reserves a unique ID for this node instance.
|
|
87
|
+
* Makes sure that the ID is not already taken by another node instance.
|
|
88
|
+
*/
|
|
89
|
+
createIdCard(): Promise<void>;
|
|
90
|
+
/**
|
|
91
|
+
* Helper method to mock worker instantiation in unit tests
|
|
92
|
+
*/
|
|
93
|
+
private constructWorker;
|
|
94
|
+
/**
|
|
95
|
+
* Start refreshing the ID Card before the worker starts to ensure the ID Card
|
|
96
|
+
* is refreshed.
|
|
97
|
+
*
|
|
98
|
+
* Once the worker starts, this timer will be stopped.
|
|
99
|
+
*/
|
|
100
|
+
private startTemporaryRefresh;
|
|
101
|
+
dispose(): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Retrieves the ID cards from other nodes
|
|
104
|
+
*
|
|
105
|
+
* Each node store it's ID Card under a specific key name. When Redis database
|
|
106
|
+
* is growing, searching for those keys can be quite expensive and can slow down
|
|
107
|
+
* the handshake process.
|
|
108
|
+
*
|
|
109
|
+
* We are storing a set containing ID Card's keys under a set so when a new node
|
|
110
|
+
* is started, it can directly get the other nodes ID Cards with SMEMBERS and
|
|
111
|
+
* then MGET instead of using SCAN.
|
|
112
|
+
*
|
|
113
|
+
* When a new node retrieve the ID Card's keys from the set, it try to get them
|
|
114
|
+
* with MGET, those who cannot be retrieved are expired ID Cards so the node update
|
|
115
|
+
* the set accordingly.
|
|
116
|
+
*
|
|
117
|
+
* @return {Array.<IdCard>}
|
|
118
|
+
*/
|
|
119
|
+
getRemoteIdCards(): Promise<IdCard[]>;
|
|
120
|
+
/**
|
|
121
|
+
* Adds a remote node IdCard to the node known topology
|
|
122
|
+
*/
|
|
123
|
+
addNode(id: string): Promise<void>;
|
|
124
|
+
/**
|
|
125
|
+
* Removes a remote node IdCard from the node known topology
|
|
126
|
+
*/
|
|
127
|
+
removeNode(id: string): Promise<void>;
|
|
128
|
+
/**
|
|
129
|
+
* Store the key under which this node ID Card is stored inside the set.
|
|
130
|
+
*
|
|
131
|
+
* This set is an index to retrieve ID Cards faster.
|
|
132
|
+
*/
|
|
133
|
+
addIdCardToIndex(): Promise<void>;
|
|
134
|
+
/**
|
|
135
|
+
* Saves the local node IdCard into Redis
|
|
136
|
+
*
|
|
137
|
+
* @returns True if the key was set
|
|
138
|
+
*/
|
|
139
|
+
private save;
|
|
140
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/*
|
|
2
3
|
* Kuzzle, a backend software, self-hostable and ready to use
|
|
3
4
|
* to power modern apps
|
|
@@ -18,231 +19,234 @@
|
|
|
18
19
|
* See the License for the specific language governing permissions and
|
|
19
20
|
* limitations under the License.
|
|
20
21
|
*/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
|
|
22
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
23
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.ClusterIdCardHandler = exports.IdCard = void 0;
|
|
27
|
+
const name_generator_1 = require("../util/name-generator");
|
|
28
|
+
const worker_threads_1 = require("worker_threads");
|
|
29
|
+
const bluebird_1 = __importDefault(require("bluebird"));
|
|
30
|
+
require("../types");
|
|
28
31
|
const REDIS_PREFIX = '{cluster/node}/';
|
|
29
32
|
const REDIS_ID_CARDS_INDEX = REDIS_PREFIX + 'id-cards-index';
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* @typedef {IdCard}
|
|
33
|
-
*/
|
|
34
33
|
class IdCard {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
id: this.id,
|
|
53
|
-
ip: this.ip,
|
|
54
|
-
topology: Array.from(this.topology),
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
static unserialize (value) {
|
|
59
|
-
return new IdCard(JSON.parse(value));
|
|
60
|
-
}
|
|
34
|
+
constructor({ id, ip, birthdate, topology }) {
|
|
35
|
+
this.id = id;
|
|
36
|
+
this.ip = ip;
|
|
37
|
+
this.birthdate = birthdate;
|
|
38
|
+
this.topology = new Set(topology);
|
|
39
|
+
}
|
|
40
|
+
serialize() {
|
|
41
|
+
return {
|
|
42
|
+
birthdate: this.birthdate,
|
|
43
|
+
id: this.id,
|
|
44
|
+
ip: this.ip,
|
|
45
|
+
topology: Array.from(this.topology),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
static unserialize(serialized) {
|
|
49
|
+
return new IdCard(serialized);
|
|
50
|
+
}
|
|
61
51
|
}
|
|
62
|
-
|
|
52
|
+
exports.IdCard = IdCard;
|
|
63
53
|
/**
|
|
64
54
|
* Handles the ID Key stored in Redis, holding node information
|
|
65
55
|
*/
|
|
66
56
|
class ClusterIdCardHandler {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
57
|
+
constructor(node) {
|
|
58
|
+
/**
|
|
59
|
+
* Local node ID Card
|
|
60
|
+
*/
|
|
61
|
+
this.idCard = null;
|
|
62
|
+
/**
|
|
63
|
+
* Multiplier used to ensure the node has enough time to refresh it's ID Card
|
|
64
|
+
* before the ID Card refresh delay
|
|
65
|
+
*/
|
|
66
|
+
this.refreshMultiplier = 2;
|
|
67
|
+
/**
|
|
68
|
+
* Worker thread in charge of refreshing the ID Card once the node has started
|
|
69
|
+
*/
|
|
70
|
+
this.refreshWorker = null;
|
|
71
|
+
/**
|
|
72
|
+
* Hold the timer in charge of refreshing the ID Card before the worker starts
|
|
73
|
+
*/
|
|
74
|
+
this.refreshTimer = null;
|
|
75
|
+
/**
|
|
76
|
+
* Local node ID
|
|
77
|
+
*/
|
|
78
|
+
this.nodeId = null;
|
|
79
|
+
/**
|
|
80
|
+
* Local node Redis key
|
|
81
|
+
*/
|
|
82
|
+
this.nodeIdKey = null;
|
|
83
|
+
/**
|
|
84
|
+
* Flag to prevent updating the id card if it has been disposed.
|
|
85
|
+
* Prevents race condition if a topology update occurs at the same time as
|
|
86
|
+
* the id card is been disposed because the node is evicting itself from the
|
|
87
|
+
* cluster
|
|
88
|
+
*/
|
|
89
|
+
this.disposed = false;
|
|
90
|
+
this.node = node;
|
|
91
|
+
this.ip = node.ip;
|
|
92
|
+
this.refreshDelay = node.heartbeatDelay;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Generates and reserves a unique ID for this node instance.
|
|
96
|
+
* Makes sure that the ID is not already taken by another node instance.
|
|
97
|
+
*/
|
|
98
|
+
async createIdCard() {
|
|
99
|
+
let reserved = false;
|
|
100
|
+
do {
|
|
101
|
+
this.nodeId = (0, name_generator_1.generateRandomName)('knode');
|
|
102
|
+
this.nodeIdKey = `${REDIS_PREFIX}${this.nodeId}`;
|
|
103
|
+
this.idCard = new IdCard({
|
|
104
|
+
birthdate: Date.now(),
|
|
105
|
+
id: this.nodeId,
|
|
106
|
+
ip: this.ip,
|
|
107
|
+
topology: [],
|
|
108
|
+
});
|
|
109
|
+
reserved = await this.save({ creation: true });
|
|
110
|
+
} while (!reserved);
|
|
111
|
+
await this.addIdCardToIndex();
|
|
112
|
+
this.refreshWorker = this.constructWorker(`${__dirname}/workers/IDCardRenewer.js`);
|
|
113
|
+
this.refreshWorker.unref();
|
|
114
|
+
this.refreshWorker.on('message', async (message) => {
|
|
115
|
+
if (message.error) {
|
|
116
|
+
await this.node.evictSelf(message.error);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
// Transfer informations to the worker
|
|
120
|
+
this.refreshWorker.postMessage({
|
|
121
|
+
action: 'start',
|
|
122
|
+
kuzzle: {
|
|
123
|
+
config: global.kuzzle.config,
|
|
124
|
+
id: global.kuzzle.id,
|
|
125
|
+
},
|
|
126
|
+
nodeIdKey: this.nodeIdKey,
|
|
127
|
+
// Used to configure a redis the same way as the Cache Engine does
|
|
128
|
+
redis: {
|
|
129
|
+
config: global.kuzzle.config.services.internalCache,
|
|
130
|
+
name: 'internal_adapter',
|
|
131
|
+
},
|
|
132
|
+
refreshDelay: this.refreshDelay,
|
|
133
|
+
refreshMultiplier: this.refreshMultiplier,
|
|
134
|
+
});
|
|
135
|
+
this.startTemporaryRefresh();
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Helper method to mock worker instantiation in unit tests
|
|
139
|
+
*/
|
|
140
|
+
constructWorker(path) {
|
|
141
|
+
return new worker_threads_1.Worker(path);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Start refreshing the ID Card before the worker starts to ensure the ID Card
|
|
145
|
+
* is refreshed.
|
|
146
|
+
*
|
|
147
|
+
* Once the worker starts, this timer will be stopped.
|
|
148
|
+
*/
|
|
149
|
+
startTemporaryRefresh() {
|
|
150
|
+
this.refreshTimer = setInterval(async () => {
|
|
151
|
+
try {
|
|
152
|
+
await this.save();
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
global.kuzzle.log.error(`An error occurred while refreshing the ID card during WorkerThread startup: ${error}`);
|
|
156
|
+
}
|
|
157
|
+
}, this.refreshDelay * this.refreshMultiplier);
|
|
158
|
+
this.refreshWorker.on('message', ({ initialized }) => {
|
|
159
|
+
if (initialized) {
|
|
160
|
+
clearInterval(this.refreshTimer);
|
|
161
|
+
this.refreshTimer = null;
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
async dispose() {
|
|
166
|
+
this.disposed = true;
|
|
167
|
+
if (this.refreshWorker) {
|
|
168
|
+
this.refreshWorker.postMessage({ action: 'dispose' });
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Retrieves the ID cards from other nodes
|
|
173
|
+
*
|
|
174
|
+
* Each node store it's ID Card under a specific key name. When Redis database
|
|
175
|
+
* is growing, searching for those keys can be quite expensive and can slow down
|
|
176
|
+
* the handshake process.
|
|
177
|
+
*
|
|
178
|
+
* We are storing a set containing ID Card's keys under a set so when a new node
|
|
179
|
+
* is started, it can directly get the other nodes ID Cards with SMEMBERS and
|
|
180
|
+
* then MGET instead of using SCAN.
|
|
181
|
+
*
|
|
182
|
+
* When a new node retrieve the ID Card's keys from the set, it try to get them
|
|
183
|
+
* with MGET, those who cannot be retrieved are expired ID Cards so the node update
|
|
184
|
+
* the set accordingly.
|
|
185
|
+
*
|
|
186
|
+
* @return {Array.<IdCard>}
|
|
187
|
+
*/
|
|
188
|
+
async getRemoteIdCards() {
|
|
189
|
+
const idCards = [];
|
|
190
|
+
let keys = await global.kuzzle.ask('core:cache:internal:execute', 'smembers', REDIS_ID_CARDS_INDEX);
|
|
191
|
+
keys = keys.filter(nodeIdKey => nodeIdKey !== this.nodeIdKey);
|
|
192
|
+
if (keys.length === 0) {
|
|
193
|
+
return idCards;
|
|
194
|
+
}
|
|
195
|
+
const rawIdCards = await global.kuzzle.ask('core:cache:internal:mget', keys);
|
|
196
|
+
const expiredIdCards = [];
|
|
197
|
+
for (let i = 0; i < keys.length; i++) {
|
|
198
|
+
// filter keys that might have expired between the key search and their
|
|
199
|
+
// values retrieval
|
|
200
|
+
if (rawIdCards[i] !== null) {
|
|
201
|
+
idCards.push(IdCard.unserialize(JSON.parse(rawIdCards[i])));
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
expiredIdCards.push(keys[i]);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// Clean expired ID Card's keys in the index
|
|
208
|
+
await bluebird_1.default.map(expiredIdCards, idCardKey => {
|
|
209
|
+
return global.kuzzle.ask('core:cache:internal:execute', 'srem', REDIS_ID_CARDS_INDEX, idCardKey);
|
|
210
|
+
});
|
|
211
|
+
return idCards;
|
|
142
212
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
* We are storing a set containing ID Card's keys under a set so when a new node
|
|
153
|
-
* is started, it can directly get the other nodes ID Cards with SMEMBERS and
|
|
154
|
-
* then MGET instead of using SCAN.
|
|
155
|
-
*
|
|
156
|
-
* When a new node retrieve the ID Card's keys from the set, it try to get them
|
|
157
|
-
* with MGET, those who cannot be retrieved are expired ID Cards so the node update
|
|
158
|
-
* the set accordingly.
|
|
159
|
-
*
|
|
160
|
-
* @return {Array.<IdCard>}
|
|
161
|
-
*/
|
|
162
|
-
async getRemoteIdCards () {
|
|
163
|
-
const idCards = [];
|
|
164
|
-
|
|
165
|
-
let keys = await global.kuzzle.ask(
|
|
166
|
-
'core:cache:internal:execute',
|
|
167
|
-
'smembers',
|
|
168
|
-
REDIS_ID_CARDS_INDEX);
|
|
169
|
-
|
|
170
|
-
keys = keys.filter(nodeIdKey => nodeIdKey !== this.nodeIdKey);
|
|
171
|
-
|
|
172
|
-
if (keys.length === 0) {
|
|
173
|
-
return idCards;
|
|
213
|
+
/**
|
|
214
|
+
* Adds a remote node IdCard to the node known topology
|
|
215
|
+
*/
|
|
216
|
+
async addNode(id) {
|
|
217
|
+
if (this.disposed || this.idCard.topology.has(id)) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
this.idCard.topology.add(id);
|
|
221
|
+
await this.save();
|
|
174
222
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
if (values[i] !== null) {
|
|
183
|
-
idCards.push(IdCard.unserialize(values[i]));
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
expiredIdCards.push(keys[i]);
|
|
187
|
-
}
|
|
223
|
+
/**
|
|
224
|
+
* Removes a remote node IdCard from the node known topology
|
|
225
|
+
*/
|
|
226
|
+
async removeNode(id) {
|
|
227
|
+
if (!this.disposed && this.idCard.topology.delete(id)) {
|
|
228
|
+
await this.save();
|
|
229
|
+
}
|
|
188
230
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
REDIS_ID_CARDS_INDEX,
|
|
196
|
-
idCardKey);
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
return idCards;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Adds a remote node IdCard to the node known topology
|
|
204
|
-
*/
|
|
205
|
-
async addNode (id) {
|
|
206
|
-
if (this.disposed || this.idCard.topology.has(id)) {
|
|
207
|
-
return;
|
|
231
|
+
/**
|
|
232
|
+
* Store the key under which this node ID Card is stored inside the set.
|
|
233
|
+
*
|
|
234
|
+
* This set is an index to retrieve ID Cards faster.
|
|
235
|
+
*/
|
|
236
|
+
async addIdCardToIndex() {
|
|
237
|
+
await global.kuzzle.ask('core:cache:internal:execute', 'sadd', REDIS_ID_CARDS_INDEX, this.nodeIdKey);
|
|
208
238
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
if (!this.disposed && this.idCard.topology.delete(id)) {
|
|
220
|
-
await this._save();
|
|
239
|
+
/**
|
|
240
|
+
* Saves the local node IdCard into Redis
|
|
241
|
+
*
|
|
242
|
+
* @returns True if the key was set
|
|
243
|
+
*/
|
|
244
|
+
async save({ creation } = { creation: false }) {
|
|
245
|
+
if (!this.idCard) {
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
return await global.kuzzle.ask('core:cache:internal:store', this.nodeIdKey, JSON.stringify(this.idCard.serialize()), { onlyIfNew: creation, ttl: this.refreshDelay * this.refreshMultiplier });
|
|
221
249
|
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* Store the key under which this node ID Card is stored inside the set.
|
|
226
|
-
*
|
|
227
|
-
* This set is an index to retrieve ID Cards faster.
|
|
228
|
-
*/
|
|
229
|
-
async addIdCardToIndex () {
|
|
230
|
-
await global.kuzzle.ask(
|
|
231
|
-
'core:cache:internal:execute',
|
|
232
|
-
'sadd',
|
|
233
|
-
REDIS_ID_CARDS_INDEX, this.nodeIdKey);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Saves the local node IdCard into Redis
|
|
238
|
-
*/
|
|
239
|
-
_save ({ creation } = { creation: false }) {
|
|
240
|
-
return global.kuzzle.ask(
|
|
241
|
-
'core:cache:internal:store',
|
|
242
|
-
this.nodeIdKey,
|
|
243
|
-
this.idCard.serialize(),
|
|
244
|
-
{ onlyIfNew: creation, ttl: this.refreshDelay * 3 });
|
|
245
|
-
}
|
|
246
250
|
}
|
|
247
|
-
|
|
248
|
-
|
|
251
|
+
exports.ClusterIdCardHandler = ClusterIdCardHandler;
|
|
252
|
+
//# sourceMappingURL=idCardHandler.js.map
|
package/lib/cluster/node.js
CHANGED
|
@@ -753,6 +753,10 @@ class ClusterNode {
|
|
|
753
753
|
* @return {void}
|
|
754
754
|
*/
|
|
755
755
|
registerEvents () {
|
|
756
|
+
global.kuzzle.on(
|
|
757
|
+
'admin:afterRefreshIndexCache',
|
|
758
|
+
() => this.onIndexCacheRefreshed());
|
|
759
|
+
|
|
756
760
|
global.kuzzle.on(
|
|
757
761
|
'core:realtime:room:create:after',
|
|
758
762
|
payload => this.onNewRealtimeRoom(payload));
|
|
@@ -1123,6 +1127,13 @@ class ClusterNode {
|
|
|
1123
1127
|
this.publisher.send('Shutdown', {});
|
|
1124
1128
|
}
|
|
1125
1129
|
|
|
1130
|
+
/**
|
|
1131
|
+
* Triggered when the index cache has been manually refreshed
|
|
1132
|
+
*/
|
|
1133
|
+
onIndexCacheRefreshed () {
|
|
1134
|
+
this.publisher.send('RefreshIndexCache', {});
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1126
1137
|
/**
|
|
1127
1138
|
* Returns the total number of subscribers on the cluster for the provided
|
|
1128
1139
|
* room
|
|
@@ -26,7 +26,6 @@ const protobuf = require('protobufjs');
|
|
|
26
26
|
const Long = require('long');
|
|
27
27
|
|
|
28
28
|
const debug = require('../util/debug')('kuzzle:cluster:sync');
|
|
29
|
-
const debugMessages = require('../util/debug')('kuzzle:cluster:messages');
|
|
30
29
|
const DocumentNotification = require('../core/realtime/notification/document');
|
|
31
30
|
const UserNotification = require('../core/realtime/notification/user');
|
|
32
31
|
const { has } = require('../util/safeObject');
|
|
@@ -41,8 +40,6 @@ const stateEnum = Object.freeze({
|
|
|
41
40
|
});
|
|
42
41
|
/* eslint-enable sort-keys */
|
|
43
42
|
|
|
44
|
-
const debugExcludedTopics = ['Heartbeat', 'UserNotification', 'DocumentNotification'];
|
|
45
|
-
|
|
46
43
|
// Handles messages received from other nodes
|
|
47
44
|
class ClusterSubscriber {
|
|
48
45
|
/**
|
|
@@ -91,6 +88,7 @@ class ClusterSubscriber {
|
|
|
91
88
|
NewRealtimeRoom: this.handleNewRealtimeRoom,
|
|
92
89
|
NodeEvicted: this.handleNodeEviction,
|
|
93
90
|
NodeShutdown: this.handleNodeShutdown,
|
|
91
|
+
RefreshIndexCache: this.handleRefreshIndexCache,
|
|
94
92
|
RefreshValidators: this.handleRefreshValidators,
|
|
95
93
|
RemoveAuthStrategy: this.handleAuthStrategyRemoval,
|
|
96
94
|
RemoveCollection: this.handleCollectionRemoval,
|
|
@@ -218,16 +216,7 @@ class ClusterSubscriber {
|
|
|
218
216
|
}
|
|
219
217
|
|
|
220
218
|
try {
|
|
221
|
-
if (! debugExcludedTopics.includes(topic)) {
|
|
222
|
-
debugMessages('[CLUSTER] "%s": %o', topic, message);
|
|
223
|
-
debugMessages('[CLUSTER] Fullstate before: %j', this.localNode.fullState.serialize());
|
|
224
|
-
}
|
|
225
|
-
|
|
226
219
|
await this.handlers[topic].call(this, message);
|
|
227
|
-
|
|
228
|
-
if (! debugExcludedTopics.includes(topic)) {
|
|
229
|
-
debugMessages('[CLUSTER] Fullstate after: %j', this.localNode.fullState.serialize());
|
|
230
|
-
}
|
|
231
220
|
}
|
|
232
221
|
catch (e) {
|
|
233
222
|
this.localNode.evictSelf(
|
|
@@ -509,6 +498,14 @@ class ClusterSubscriber {
|
|
|
509
498
|
await global.kuzzle.validation.curateSpecification();
|
|
510
499
|
}
|
|
511
500
|
|
|
501
|
+
/**
|
|
502
|
+
* Handles manual refresh of the index cache
|
|
503
|
+
*/
|
|
504
|
+
async handleRefreshIndexCache () {
|
|
505
|
+
debug('Index cache manually refresh received from node %s', this.remoteNodeId);
|
|
506
|
+
await global.kuzzle.ask('core:storage:public:cache:refresh', { from: 'cluster' });
|
|
507
|
+
}
|
|
508
|
+
|
|
512
509
|
/**
|
|
513
510
|
* Invalidates a profile to force reloading it from the storage space
|
|
514
511
|
*
|