@naturalcycles/datastore-lib 3.23.2 → 3.24.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/dist/datastore.db.d.ts +1 -0
- package/dist/datastore.db.js +36 -32
- package/dist/datastore.model.d.ts +2 -2
- package/package.json +1 -1
- package/src/datastore.db.ts +40 -35
- package/src/datastore.model.ts +2 -2
package/dist/datastore.db.d.ts
CHANGED
|
@@ -57,4 +57,5 @@ export declare class DatastoreDB extends BaseCommonDB implements CommonDB {
|
|
|
57
57
|
getKey(key: Key): string | undefined;
|
|
58
58
|
getTables(): Promise<string[]>;
|
|
59
59
|
getTableSchema<ROW extends ObjectWithId>(table: string): Promise<JsonSchemaRootObject<ROW>>;
|
|
60
|
+
private getPRetryOptions;
|
|
60
61
|
}
|
package/dist/datastore.db.js
CHANGED
|
@@ -155,19 +155,7 @@ class DatastoreDB extends db_lib_1.BaseCommonDB {
|
|
|
155
155
|
const method = methodMap[opt.saveMethod || 'upsert'] || 'save';
|
|
156
156
|
const save = (0, js_lib_1.pRetryFn)(async (batch) => {
|
|
157
157
|
await (opt.tx || this.ds())[method](batch);
|
|
158
|
-
}, {
|
|
159
|
-
// Here we retry the GOAWAY errors that are somewhat common for Datastore
|
|
160
|
-
// Currently only retrying them here in .saveBatch(), cause probably they're only thrown when saving
|
|
161
|
-
predicate: err => RETRY_ON.some(s => err?.message?.includes(s)),
|
|
162
|
-
name: `DatastoreLib.saveBatch(${table})`,
|
|
163
|
-
maxAttempts: 5,
|
|
164
|
-
delay: 5000,
|
|
165
|
-
delayMultiplier: 2,
|
|
166
|
-
logFirstAttempt: false,
|
|
167
|
-
logFailures: true,
|
|
168
|
-
// logAll: true,
|
|
169
|
-
logger: this.cfg.logger,
|
|
170
|
-
});
|
|
158
|
+
}, this.getPRetryOptions(`DatastoreLib.saveBatch(${table})`));
|
|
171
159
|
try {
|
|
172
160
|
const chunks = (0, js_lib_1._chunk)(entities, MAX_ITEMS);
|
|
173
161
|
if (chunks.length === 1) {
|
|
@@ -203,27 +191,30 @@ class DatastoreDB extends db_lib_1.BaseCommonDB {
|
|
|
203
191
|
* https://cloud.google.com/datastore/docs/concepts/transactions#datastore-datastore-transactional-update-nodejs
|
|
204
192
|
*/
|
|
205
193
|
async commitTransaction(_tx, opt) {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
194
|
+
// Using Retry, because Datastore can throw errors like "too much contention" here
|
|
195
|
+
await (0, js_lib_1.pRetry)(async () => {
|
|
196
|
+
const tx = this.ds().transaction();
|
|
197
|
+
try {
|
|
198
|
+
await tx.run();
|
|
199
|
+
const ops = (0, db_lib_1.mergeDBOperations)(_tx.ops);
|
|
200
|
+
for await (const op of ops) {
|
|
201
|
+
if (op.type === 'saveBatch') {
|
|
202
|
+
await this.saveBatch(op.table, op.rows, { ...opt, tx });
|
|
203
|
+
}
|
|
204
|
+
else if (op.type === 'deleteByIds') {
|
|
205
|
+
await this.deleteByIds(op.table, op.ids, { ...opt, tx });
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
throw new Error(`DBOperation not supported: ${op.type}`);
|
|
209
|
+
}
|
|
219
210
|
}
|
|
211
|
+
await tx.commit();
|
|
220
212
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
}
|
|
213
|
+
catch (err) {
|
|
214
|
+
await tx.rollback();
|
|
215
|
+
throw err; // rethrow
|
|
216
|
+
}
|
|
217
|
+
}, this.getPRetryOptions(`DatastoreLib.commitTransaction`));
|
|
227
218
|
}
|
|
228
219
|
async getAllStats() {
|
|
229
220
|
const q = this.ds().createQuery('__Stat_Kind__');
|
|
@@ -356,5 +347,18 @@ class DatastoreDB extends db_lib_1.BaseCommonDB {
|
|
|
356
347
|
});
|
|
357
348
|
return s;
|
|
358
349
|
}
|
|
350
|
+
getPRetryOptions(name) {
|
|
351
|
+
return {
|
|
352
|
+
predicate: err => RETRY_ON.some(s => err?.message?.includes(s)),
|
|
353
|
+
name,
|
|
354
|
+
maxAttempts: 5,
|
|
355
|
+
delay: 5000,
|
|
356
|
+
delayMultiplier: 2,
|
|
357
|
+
logFirstAttempt: false,
|
|
358
|
+
logFailures: true,
|
|
359
|
+
// logAll: true,
|
|
360
|
+
logger: this.cfg.logger,
|
|
361
|
+
};
|
|
362
|
+
}
|
|
359
363
|
}
|
|
360
364
|
exports.DatastoreDB = DatastoreDB;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DatastoreOptions, Key, Transaction } from '@google-cloud/datastore';
|
|
2
2
|
import { CommonDBOptions, CommonDBSaveOptions } from '@naturalcycles/db-lib';
|
|
3
|
-
import {
|
|
3
|
+
import { CommonLogger, ObjectWithId } from '@naturalcycles/js-lib';
|
|
4
4
|
export interface DatastorePayload<T = any> {
|
|
5
5
|
key: Key;
|
|
6
6
|
data: T;
|
|
@@ -99,7 +99,7 @@ export interface DatastoreDBStreamOptions extends DatastoreDBOptions {
|
|
|
99
99
|
export interface DatastoreDBOptions extends CommonDBOptions {
|
|
100
100
|
tx?: Transaction;
|
|
101
101
|
}
|
|
102
|
-
export interface DatastoreDBSaveOptions<ROW extends Partial<ObjectWithId> =
|
|
102
|
+
export interface DatastoreDBSaveOptions<ROW extends Partial<ObjectWithId> = any> extends CommonDBSaveOptions<ROW> {
|
|
103
103
|
tx?: Transaction;
|
|
104
104
|
}
|
|
105
105
|
export interface DatastoreStats {
|
package/package.json
CHANGED
package/src/datastore.db.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
CommonDBSaveMethod,
|
|
7
7
|
DBQuery,
|
|
8
8
|
DBTransaction,
|
|
9
|
+
mergeDBOperations,
|
|
9
10
|
RunQueryResult,
|
|
10
11
|
} from '@naturalcycles/db-lib'
|
|
11
12
|
import {
|
|
@@ -25,6 +26,8 @@ import {
|
|
|
25
26
|
commonLoggerMinLevel,
|
|
26
27
|
pTimeout,
|
|
27
28
|
pRetryFn,
|
|
29
|
+
pRetry,
|
|
30
|
+
PRetryOptions,
|
|
28
31
|
} from '@naturalcycles/js-lib'
|
|
29
32
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib'
|
|
30
33
|
import { boldWhite } from '@naturalcycles/nodejs-lib/dist/colors'
|
|
@@ -255,24 +258,9 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
|
|
|
255
258
|
|
|
256
259
|
const method = methodMap[opt.saveMethod || 'upsert'] || 'save'
|
|
257
260
|
|
|
258
|
-
const save = pRetryFn(
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
},
|
|
262
|
-
{
|
|
263
|
-
// Here we retry the GOAWAY errors that are somewhat common for Datastore
|
|
264
|
-
// Currently only retrying them here in .saveBatch(), cause probably they're only thrown when saving
|
|
265
|
-
predicate: err => RETRY_ON.some(s => err?.message?.includes(s)),
|
|
266
|
-
name: `DatastoreLib.saveBatch(${table})`,
|
|
267
|
-
maxAttempts: 5,
|
|
268
|
-
delay: 5000,
|
|
269
|
-
delayMultiplier: 2,
|
|
270
|
-
logFirstAttempt: false,
|
|
271
|
-
logFailures: true,
|
|
272
|
-
// logAll: true,
|
|
273
|
-
logger: this.cfg.logger,
|
|
274
|
-
},
|
|
275
|
-
)
|
|
261
|
+
const save = pRetryFn(async (batch: DatastorePayload<ROW>[]) => {
|
|
262
|
+
await (opt.tx || this.ds())[method](batch)
|
|
263
|
+
}, this.getPRetryOptions(`DatastoreLib.saveBatch(${table})`))
|
|
276
264
|
|
|
277
265
|
try {
|
|
278
266
|
const chunks = _chunk(entities, MAX_ITEMS)
|
|
@@ -328,28 +316,31 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
|
|
|
328
316
|
_tx: DBTransaction,
|
|
329
317
|
opt?: DatastoreDBSaveOptions,
|
|
330
318
|
): Promise<void> {
|
|
331
|
-
|
|
319
|
+
// Using Retry, because Datastore can throw errors like "too much contention" here
|
|
320
|
+
await pRetry(async () => {
|
|
321
|
+
const tx = this.ds().transaction()
|
|
332
322
|
|
|
333
|
-
|
|
334
|
-
|
|
323
|
+
try {
|
|
324
|
+
await tx.run()
|
|
335
325
|
|
|
336
|
-
|
|
326
|
+
const ops = mergeDBOperations(_tx.ops)
|
|
337
327
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
328
|
+
for await (const op of ops) {
|
|
329
|
+
if (op.type === 'saveBatch') {
|
|
330
|
+
await this.saveBatch(op.table, op.rows, { ...opt, tx })
|
|
331
|
+
} else if (op.type === 'deleteByIds') {
|
|
332
|
+
await this.deleteByIds(op.table, op.ids, { ...opt, tx })
|
|
333
|
+
} else {
|
|
334
|
+
throw new Error(`DBOperation not supported: ${(op as any).type}`)
|
|
335
|
+
}
|
|
345
336
|
}
|
|
346
|
-
}
|
|
347
337
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
338
|
+
await tx.commit()
|
|
339
|
+
} catch (err) {
|
|
340
|
+
await tx.rollback()
|
|
341
|
+
throw err // rethrow
|
|
342
|
+
}
|
|
343
|
+
}, this.getPRetryOptions(`DatastoreLib.commitTransaction`))
|
|
353
344
|
}
|
|
354
345
|
|
|
355
346
|
async getAllStats(): Promise<DatastoreStats[]> {
|
|
@@ -496,4 +487,18 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
|
|
|
496
487
|
|
|
497
488
|
return s
|
|
498
489
|
}
|
|
490
|
+
|
|
491
|
+
private getPRetryOptions(name: string): PRetryOptions {
|
|
492
|
+
return {
|
|
493
|
+
predicate: err => RETRY_ON.some(s => err?.message?.includes(s)),
|
|
494
|
+
name,
|
|
495
|
+
maxAttempts: 5,
|
|
496
|
+
delay: 5000,
|
|
497
|
+
delayMultiplier: 2,
|
|
498
|
+
logFirstAttempt: false,
|
|
499
|
+
logFailures: true,
|
|
500
|
+
// logAll: true,
|
|
501
|
+
logger: this.cfg.logger,
|
|
502
|
+
}
|
|
503
|
+
}
|
|
499
504
|
}
|
package/src/datastore.model.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DatastoreOptions, Key, Transaction } from '@google-cloud/datastore'
|
|
2
2
|
import { CommonDBOptions, CommonDBSaveOptions } from '@naturalcycles/db-lib'
|
|
3
|
-
import {
|
|
3
|
+
import { CommonLogger, ObjectWithId } from '@naturalcycles/js-lib'
|
|
4
4
|
|
|
5
5
|
export interface DatastorePayload<T = any> {
|
|
6
6
|
key: Key
|
|
@@ -114,7 +114,7 @@ export interface DatastoreDBStreamOptions extends DatastoreDBOptions {
|
|
|
114
114
|
export interface DatastoreDBOptions extends CommonDBOptions {
|
|
115
115
|
tx?: Transaction
|
|
116
116
|
}
|
|
117
|
-
export interface DatastoreDBSaveOptions<ROW extends Partial<ObjectWithId> =
|
|
117
|
+
export interface DatastoreDBSaveOptions<ROW extends Partial<ObjectWithId> = any>
|
|
118
118
|
extends CommonDBSaveOptions<ROW> {
|
|
119
119
|
tx?: Transaction
|
|
120
120
|
}
|