kuzzle 2.60.0-beta.2 → 2.60.0-beta.4
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/dist/bin/start-kuzzle-server +2 -1
- package/dist/lib/api/controllers/documentController.d.ts +1 -1
- package/dist/lib/cluster/command.d.ts +7 -0
- package/dist/lib/cluster/command.js +67 -28
- package/dist/lib/cluster/idCardHandler.d.ts +4 -0
- package/dist/lib/cluster/idCardHandler.js +23 -2
- package/dist/lib/cluster/node.d.ts +28 -5
- package/dist/lib/cluster/node.js +159 -76
- package/dist/lib/cluster/subscriber.d.ts +2 -0
- package/dist/lib/cluster/subscriber.js +6 -0
- package/dist/lib/cluster/workers/IDCardRenewer.d.ts +6 -0
- package/dist/lib/cluster/workers/IDCardRenewer.js +14 -8
- package/dist/lib/core/auth/passportWrapper.js +3 -1
- package/dist/lib/core/backend/backend.d.ts +1 -1
- package/dist/lib/core/backend/backend.js +15 -15
- package/dist/lib/core/backend/backendCluster.d.ts +1 -1
- package/dist/lib/core/shared/store.js +4 -0
- package/dist/lib/core/storage/clientAdapter.d.ts +6 -0
- package/dist/lib/core/storage/clientAdapter.js +35 -5
- package/dist/lib/kerror/codes/8-cluster.json +23 -0
- package/dist/lib/kuzzle/exitOnFailure.d.ts +13 -0
- package/dist/lib/kuzzle/exitOnFailure.js +60 -0
- package/dist/lib/kuzzle/internalIndexHandler.js +24 -6
- package/dist/lib/kuzzle/kuzzle.d.ts +7 -0
- package/dist/lib/kuzzle/kuzzle.js +45 -2
- package/dist/lib/model/security/profile.d.ts +1 -1
- package/dist/lib/model/security/role.d.ts +1 -1
- package/dist/lib/model/security/user.d.ts +1 -1
- package/dist/lib/service/storage/7/elasticsearch.d.ts +12 -0
- package/dist/lib/service/storage/7/elasticsearch.js +32 -1
- package/dist/lib/service/storage/7/esWrapper.js +31 -2
- package/dist/lib/service/storage/8/elasticsearch.d.ts +12 -0
- package/dist/lib/service/storage/8/elasticsearch.js +32 -1
- package/dist/lib/service/storage/8/esWrapper.js +31 -2
- package/dist/lib/types/events/EventGenericDocument.d.ts +2 -1
- package/dist/lib/types/events/EventProtocol.d.ts +1 -1
- package/dist/lib/util/mutex.d.ts +2 -1
- package/dist/lib/util/mutex.js +7 -1
- package/dist/package.json +1 -1
- package/package.json +1 -1
|
@@ -89,6 +89,9 @@ const HIDDEN_COLLECTION = "_kuzzle_keep";
|
|
|
89
89
|
// is refreshed while held, so a live holder is never overtaken; a crashed
|
|
90
90
|
// one leaves it for at most `ttl` (30 s).
|
|
91
91
|
const HIDDEN_COLLECTION_LOCK = { retryAttempts: Number.POSITIVE_INFINITY };
|
|
92
|
+
// How long `waitForCollectionShards` lets Elasticsearch wait for a
|
|
93
|
+
// collection's primary shards, which is also Elasticsearch's own default
|
|
94
|
+
const COLLECTION_SHARDS_TIMEOUT = "30s";
|
|
92
95
|
const ALIAS_PREFIX = "@"; // @todo next major release: Add ALIAS_PREFIX in FORBIDDEN_CHARS
|
|
93
96
|
const PRIVATE_PREFIX = "%";
|
|
94
97
|
const PUBLIC_PREFIX = "&";
|
|
@@ -1168,6 +1171,9 @@ class ES8 {
|
|
|
1168
1171
|
this._checkDynamicProperty(mappings);
|
|
1169
1172
|
const exists = await this.hasCollection(index, collection);
|
|
1170
1173
|
if (exists) {
|
|
1174
|
+
// Another node created it, maybe so recently that its primary shards
|
|
1175
|
+
// are still initializing
|
|
1176
|
+
await this.waitForCollectionShards(index, collection);
|
|
1171
1177
|
return this.updateCollection(index, collection, { mappings, settings });
|
|
1172
1178
|
}
|
|
1173
1179
|
this._checkMappings(mappings);
|
|
@@ -1189,7 +1195,9 @@ class ES8 {
|
|
|
1189
1195
|
if (lodash_1.default.get(error, "meta.body.error.type") ===
|
|
1190
1196
|
"resource_already_exists_exception") {
|
|
1191
1197
|
// race condition: the indice has been created between the "exists"
|
|
1192
|
-
// check above and this "create" attempt
|
|
1198
|
+
// check above and this "create" attempt, by a request that may not
|
|
1199
|
+
// have waited for its shards yet
|
|
1200
|
+
await this.waitForCollectionShards(index, collection);
|
|
1193
1201
|
return null;
|
|
1194
1202
|
}
|
|
1195
1203
|
throw this._esWrapper.formatESError(error);
|
|
@@ -1209,6 +1217,29 @@ class ES8 {
|
|
|
1209
1217
|
}
|
|
1210
1218
|
return null;
|
|
1211
1219
|
}
|
|
1220
|
+
/**
|
|
1221
|
+
* Waits until the primary shards of a collection are active, for at most
|
|
1222
|
+
* `timeout`, and rejects if they are not by then.
|
|
1223
|
+
*
|
|
1224
|
+
* A collection another node has just created is in the cluster state, so
|
|
1225
|
+
* it exists, before its primary shard is active: until then, Elasticsearch
|
|
1226
|
+
* answers 503 to any document request on it. The node that creates a
|
|
1227
|
+
* collection waits for its shards (`wait_for_active_shards`); a node that
|
|
1228
|
+
* finds it already there calls this instead. It answers at once when the
|
|
1229
|
+
* shards are already active.
|
|
1230
|
+
*/
|
|
1231
|
+
async waitForCollectionShards(index, collection, timeout = COLLECTION_SHARDS_TIMEOUT) {
|
|
1232
|
+
try {
|
|
1233
|
+
await this._client.cluster.health({
|
|
1234
|
+
index: this._getAlias(index, collection),
|
|
1235
|
+
timeout,
|
|
1236
|
+
wait_for_status: "yellow",
|
|
1237
|
+
});
|
|
1238
|
+
}
|
|
1239
|
+
catch (error) {
|
|
1240
|
+
throw this._esWrapper.formatESError(error);
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1212
1243
|
/**
|
|
1213
1244
|
* Retrieves settings definition for index/type
|
|
1214
1245
|
*
|
|
@@ -35,6 +35,35 @@ const kerror = (0, kerror_1.wrap)("services", "storage");
|
|
|
35
35
|
function isResponseError(error) {
|
|
36
36
|
return Boolean(error.meta);
|
|
37
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* What the client puts in `message` when the response carried nothing it could
|
|
40
|
+
* read: this placeholder, or an empty string for a bodyless response.
|
|
41
|
+
*/
|
|
42
|
+
const CLIENT_PLACEHOLDER_MESSAGE = "Response Error";
|
|
43
|
+
function isUsableMessage(message) {
|
|
44
|
+
return (typeof message === "string" &&
|
|
45
|
+
message.trim() !== "" &&
|
|
46
|
+
message !== CLIENT_PLACEHOLDER_MESSAGE);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A message for an error that came with none worth keeping (typically a 503
|
|
50
|
+
* with no body while shards initialize), built from what the error still
|
|
51
|
+
* carries: the client's error name, the HTTP status and the response body.
|
|
52
|
+
*/
|
|
53
|
+
function describeUnreadableError(error) {
|
|
54
|
+
const statusCode = error.meta?.statusCode;
|
|
55
|
+
const body = error.meta?.body;
|
|
56
|
+
const hasBody = body !== undefined && body !== null && body !== "";
|
|
57
|
+
let description = statusCode === undefined
|
|
58
|
+
? "Elasticsearch request failed"
|
|
59
|
+
: `Elasticsearch responded ${statusCode}`;
|
|
60
|
+
description += hasBody
|
|
61
|
+
? `: ${(0, node_util_1.inspect)(body, { breakLength: Infinity, depth: 3 })}`
|
|
62
|
+
: " (no body)";
|
|
63
|
+
return error.name && error.name !== "Error"
|
|
64
|
+
? `${error.name}: ${description}`
|
|
65
|
+
: description;
|
|
66
|
+
}
|
|
38
67
|
const errorMessagesMapping = [
|
|
39
68
|
{
|
|
40
69
|
regex: /^\[es_rejected_execution_exception] rejected execution .*? on EsThreadPoolExecutor\[(.*?), .*$/,
|
|
@@ -258,8 +287,8 @@ class ESWrapper {
|
|
|
258
287
|
return kerror.get("unexpected_bad_request", errorMessage);
|
|
259
288
|
}
|
|
260
289
|
_handleUnknownError(error, message) {
|
|
261
|
-
debug("unhandled elasticsearch error (unhandled type: %s): %o", (0, get_1.default)(error, "
|
|
262
|
-
return kerror.get("unexpected_error", message);
|
|
290
|
+
debug("unhandled elasticsearch error (unhandled type: %s): %o", (0, get_1.default)(error, "meta.statusCode", "<no status code>"), error);
|
|
291
|
+
return kerror.get("unexpected_error", isUsableMessage(message) ? message : describeUnreadableError(error));
|
|
263
292
|
}
|
|
264
293
|
}
|
|
265
294
|
module.exports = ESWrapper;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { KDocument, KDocumentContent } from "kuzzle-types";
|
|
2
2
|
import type { JSONObject } from "../JSONObject";
|
|
3
|
-
import type { KuzzleRequest
|
|
3
|
+
import type { KuzzleRequest } from "../../api/request";
|
|
4
|
+
import type { PipeEventHandler } from "../EventHandler";
|
|
4
5
|
/**
|
|
5
6
|
* Events with documents only having the `_id`
|
|
6
7
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { JSONObject } from "../JSONObject";
|
|
2
|
-
import type { PipeEventHandler } from "
|
|
2
|
+
import type { PipeEventHandler } from "../EventHandler";
|
|
3
3
|
import type { ClientConnection } from "../ClientConnection";
|
|
4
4
|
import type { HttpMessage } from "../HttpMessage";
|
|
5
5
|
export type EventHTTPBeforeParsingPayload = {
|
package/dist/lib/util/mutex.d.ts
CHANGED
|
@@ -101,7 +101,8 @@ export declare class Mutex {
|
|
|
101
101
|
*
|
|
102
102
|
* From then on, `lock()` never resolves: the process is about to exit, and
|
|
103
103
|
* answering `false` would send its caller down a path meant for a lock
|
|
104
|
-
* held by another node.
|
|
104
|
+
* held by another node. And `unlock()` on a lock it already freed resolves
|
|
105
|
+
* without doing anything, since its holder may still try to give it back.
|
|
105
106
|
*/
|
|
106
107
|
static releaseAllBeforeExit(): Promise<void>;
|
|
107
108
|
get locked(): boolean;
|
package/dist/lib/util/mutex.js
CHANGED
|
@@ -165,6 +165,11 @@ class Mutex {
|
|
|
165
165
|
* @return {Promise}
|
|
166
166
|
*/
|
|
167
167
|
async unlock() {
|
|
168
|
+
// `releaseAllBeforeExit` already gave this lock back: its holder is only
|
|
169
|
+
// catching up, and throwing would turn a requested shutdown into a crash.
|
|
170
|
+
if (!this._locked && exiting) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
168
173
|
if (!this._locked) {
|
|
169
174
|
throw fatal.get("assertion_failed", `tried to unlock the resource "${this.resource}", which is not locked (mutex id: ${this.mutexId})`);
|
|
170
175
|
}
|
|
@@ -214,7 +219,8 @@ class Mutex {
|
|
|
214
219
|
*
|
|
215
220
|
* From then on, `lock()` never resolves: the process is about to exit, and
|
|
216
221
|
* answering `false` would send its caller down a path meant for a lock
|
|
217
|
-
* held by another node.
|
|
222
|
+
* held by another node. And `unlock()` on a lock it already freed resolves
|
|
223
|
+
* without doing anything, since its holder may still try to give it back.
|
|
218
224
|
*/
|
|
219
225
|
static async releaseAllBeforeExit() {
|
|
220
226
|
exiting = true;
|
package/dist/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kuzzle",
|
|
3
3
|
"author": "The Kuzzle Team <support@kuzzle.io>",
|
|
4
|
-
"version": "2.60.0-beta.
|
|
4
|
+
"version": "2.60.0-beta.4",
|
|
5
5
|
"description": "Kuzzle is an open-source solution that handles all the data management through a secured API, with a large choice of protocols.",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"build": "rm -Rf ./dist && tsc && node -r ts-node/register/transpile-only ./bin/copy-binaries.ts",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kuzzle",
|
|
3
3
|
"author": "The Kuzzle Team <support@kuzzle.io>",
|
|
4
|
-
"version": "2.60.0-beta.
|
|
4
|
+
"version": "2.60.0-beta.4",
|
|
5
5
|
"description": "Kuzzle is an open-source solution that handles all the data management through a secured API, with a large choice of protocols.",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"build": "rm -Rf ./dist && tsc && node -r ts-node/register/transpile-only ./bin/copy-binaries.ts",
|