@naturalcycles/datastore-lib 3.17.0 → 3.18.1
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/datastore.db.js +26 -4
- package/dist/datastore.model.d.ts +7 -0
- package/dist/datastoreKeyValueDB.d.ts +1 -0
- package/dist/datastoreKeyValueDB.js +4 -0
- package/package.json +2 -2
- package/src/datastore.db.ts +31 -4
- package/src/datastore.model.ts +8 -0
- package/src/datastoreKeyValueDB.ts +5 -0
package/dist/datastore.db.js
CHANGED
|
@@ -55,9 +55,29 @@ class DatastoreDB extends db_lib_1.BaseCommonDB {
|
|
|
55
55
|
if (!ids.length)
|
|
56
56
|
return [];
|
|
57
57
|
const keys = ids.map(id => this.key(table, id));
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
let rows;
|
|
59
|
+
try {
|
|
60
|
+
if (this.cfg.timeout) {
|
|
61
|
+
const r = await (0, js_lib_1.pTimeout)(this.ds().get(keys), {
|
|
62
|
+
timeout: this.cfg.timeout,
|
|
63
|
+
name: `datastore.getByIds(${table})`,
|
|
64
|
+
});
|
|
65
|
+
rows = r[0];
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
rows = (await this.ds().get(keys))[0];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
this.cfg.logger.log('datastore recreated on error');
|
|
73
|
+
// This is to debug "GCP Datastore Timeout issue"
|
|
74
|
+
const datastoreLib = require('@google-cloud/datastore');
|
|
75
|
+
const DS = datastoreLib.Datastore;
|
|
76
|
+
this.cachedDatastore = new DS(this.cfg);
|
|
77
|
+
throw err;
|
|
78
|
+
}
|
|
79
|
+
return (rows
|
|
80
|
+
.map(r => this.mapId(r))
|
|
61
81
|
// Seems like datastore .get() method doesn't return items properly sorted by input ids, so we gonna sort them here
|
|
62
82
|
// same ids are not expected here
|
|
63
83
|
.sort((a, b) => (a.id > b.id ? 1 : -1)));
|
|
@@ -119,19 +139,21 @@ class DatastoreDB extends db_lib_1.BaseCommonDB {
|
|
|
119
139
|
// Here we retry the GOAWAY errors that are somewhat common for Datastore
|
|
120
140
|
// Currently only retrying them here in .saveBatch(), cause probably they're only thrown when saving
|
|
121
141
|
predicate: err => RETRY_ON.some(s => err?.message.includes(s)),
|
|
142
|
+
name: `DatastoreLib.saveBatch(${table})`,
|
|
122
143
|
maxAttempts: 5,
|
|
123
144
|
delay: 5000,
|
|
124
145
|
delayMultiplier: 2,
|
|
125
146
|
logFirstAttempt: false,
|
|
126
147
|
logFailures: true,
|
|
127
148
|
// logAll: true,
|
|
149
|
+
logger: this.cfg.logger,
|
|
128
150
|
});
|
|
129
151
|
try {
|
|
130
152
|
await (0, js_lib_1.pMap)((0, js_lib_1._chunk)(entities, MAX_ITEMS), async (batch) => await save(batch));
|
|
131
153
|
}
|
|
132
154
|
catch (err) {
|
|
133
155
|
// console.log(`datastore.save ${kind}`, { obj, entity })
|
|
134
|
-
this.cfg.logger.error(`error in
|
|
156
|
+
this.cfg.logger.error(`error in DatastoreLib.saveBatch for ${table} (${rows.length} rows)`, err);
|
|
135
157
|
// don't throw, because datastore SDK makes it in separate thread, so exception will be unhandled otherwise
|
|
136
158
|
return await Promise.reject(err);
|
|
137
159
|
}
|
|
@@ -34,6 +34,13 @@ export interface DatastoreDBCfg extends DatastoreOptions {
|
|
|
34
34
|
* Default to `console`
|
|
35
35
|
*/
|
|
36
36
|
logger?: CommonLogger;
|
|
37
|
+
/**
|
|
38
|
+
* Experimental option, currently only applies to `getByIds`.
|
|
39
|
+
* Applies pTimeout to Datastore operation, re-creates Datastore on any error.
|
|
40
|
+
*
|
|
41
|
+
* @experimental
|
|
42
|
+
*/
|
|
43
|
+
timeout?: number;
|
|
37
44
|
}
|
|
38
45
|
export interface DatastoreCredentials {
|
|
39
46
|
type?: string;
|
|
@@ -17,4 +17,5 @@ export declare class DatastoreKeyValueDB implements CommonKeyValueDB {
|
|
|
17
17
|
streamIds(table: string, limit?: number): ReadableTyped<string>;
|
|
18
18
|
streamValues(table: string, limit?: number): ReadableTyped<Buffer>;
|
|
19
19
|
streamEntries(table: string, limit?: number): ReadableTyped<KeyValueDBTuple>;
|
|
20
|
+
count(_table: string): Promise<number>;
|
|
20
21
|
}
|
|
@@ -47,5 +47,9 @@ class DatastoreKeyValueDB {
|
|
|
47
47
|
errorMode: js_lib_1.ErrorMode.SUPPRESS, // cause .pipe() cannot propagate errors
|
|
48
48
|
}));
|
|
49
49
|
}
|
|
50
|
+
async count(_table) {
|
|
51
|
+
this.db.cfg.logger.warn(`DatastoreKeyValueDB.count is not supported`);
|
|
52
|
+
return 0;
|
|
53
|
+
}
|
|
50
54
|
}
|
|
51
55
|
exports.DatastoreKeyValueDB = DatastoreKeyValueDB;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naturalcycles/datastore-lib",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.18.1",
|
|
4
4
|
"description": "Opinionated library to work with Google Datastore",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"prepare": "husky install"
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"@google-cloud/datastore": "^6.0.0",
|
|
19
19
|
"@naturalcycles/dev-lib": "^12.0.1",
|
|
20
|
-
"@types/node": "^
|
|
20
|
+
"@types/node": "^17.0.8",
|
|
21
21
|
"jest": "^27.0.4"
|
|
22
22
|
},
|
|
23
23
|
"files": [
|
package/src/datastore.db.ts
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
JsonSchemaRootObject,
|
|
25
25
|
CommonLogger,
|
|
26
26
|
commonLoggerMinLevel,
|
|
27
|
+
pTimeout,
|
|
27
28
|
} from '@naturalcycles/js-lib'
|
|
28
29
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib'
|
|
29
30
|
import { boldWhite } from '@naturalcycles/nodejs-lib/dist/colors'
|
|
@@ -113,11 +114,32 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
|
|
|
113
114
|
): Promise<ROW[]> {
|
|
114
115
|
if (!ids.length) return []
|
|
115
116
|
const keys = ids.map(id => this.key(table, id))
|
|
116
|
-
|
|
117
|
+
let rows: any[]
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
if (this.cfg.timeout) {
|
|
121
|
+
const r = await pTimeout(this.ds().get(keys), {
|
|
122
|
+
timeout: this.cfg.timeout,
|
|
123
|
+
name: `datastore.getByIds(${table})`,
|
|
124
|
+
})
|
|
125
|
+
rows = r[0]
|
|
126
|
+
} else {
|
|
127
|
+
rows = (await this.ds().get(keys))[0]
|
|
128
|
+
}
|
|
129
|
+
} catch (err) {
|
|
130
|
+
this.cfg.logger.log('datastore recreated on error')
|
|
131
|
+
|
|
132
|
+
// This is to debug "GCP Datastore Timeout issue"
|
|
133
|
+
const datastoreLib = require('@google-cloud/datastore')
|
|
134
|
+
const DS = datastoreLib.Datastore as typeof Datastore
|
|
135
|
+
this.cachedDatastore = new DS(this.cfg)
|
|
136
|
+
|
|
137
|
+
throw err
|
|
138
|
+
}
|
|
117
139
|
|
|
118
140
|
return (
|
|
119
|
-
|
|
120
|
-
.map(
|
|
141
|
+
rows
|
|
142
|
+
.map(r => this.mapId<ROW>(r))
|
|
121
143
|
// Seems like datastore .get() method doesn't return items properly sorted by input ids, so we gonna sort them here
|
|
122
144
|
// same ids are not expected here
|
|
123
145
|
.sort((a, b) => (a.id > b.id ? 1 : -1))
|
|
@@ -221,12 +243,14 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
|
|
|
221
243
|
// Here we retry the GOAWAY errors that are somewhat common for Datastore
|
|
222
244
|
// Currently only retrying them here in .saveBatch(), cause probably they're only thrown when saving
|
|
223
245
|
predicate: err => RETRY_ON.some(s => (err as Error)?.message.includes(s)),
|
|
246
|
+
name: `DatastoreLib.saveBatch(${table})`,
|
|
224
247
|
maxAttempts: 5,
|
|
225
248
|
delay: 5000,
|
|
226
249
|
delayMultiplier: 2,
|
|
227
250
|
logFirstAttempt: false,
|
|
228
251
|
logFailures: true,
|
|
229
252
|
// logAll: true,
|
|
253
|
+
logger: this.cfg.logger,
|
|
230
254
|
},
|
|
231
255
|
)
|
|
232
256
|
|
|
@@ -234,7 +258,10 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
|
|
|
234
258
|
await pMap(_chunk(entities, MAX_ITEMS), async batch => await save(batch))
|
|
235
259
|
} catch (err) {
|
|
236
260
|
// console.log(`datastore.save ${kind}`, { obj, entity })
|
|
237
|
-
this.cfg.logger.error(
|
|
261
|
+
this.cfg.logger.error(
|
|
262
|
+
`error in DatastoreLib.saveBatch for ${table} (${rows.length} rows)`,
|
|
263
|
+
err,
|
|
264
|
+
)
|
|
238
265
|
// don't throw, because datastore SDK makes it in separate thread, so exception will be unhandled otherwise
|
|
239
266
|
return await Promise.reject(err)
|
|
240
267
|
}
|
package/src/datastore.model.ts
CHANGED
|
@@ -41,6 +41,14 @@ export interface DatastoreDBCfg extends DatastoreOptions {
|
|
|
41
41
|
* Default to `console`
|
|
42
42
|
*/
|
|
43
43
|
logger?: CommonLogger
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Experimental option, currently only applies to `getByIds`.
|
|
47
|
+
* Applies pTimeout to Datastore operation, re-creates Datastore on any error.
|
|
48
|
+
*
|
|
49
|
+
* @experimental
|
|
50
|
+
*/
|
|
51
|
+
timeout?: number
|
|
44
52
|
}
|
|
45
53
|
|
|
46
54
|
export interface DatastoreCredentials {
|