@lokalise/prisma-utils 7.0.1 → 7.1.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/README.md +32 -0
- package/dist/errors/cockroachdbError.d.ts +5 -0
- package/dist/errors/cockroachdbError.js +16 -2
- package/dist/errors/cockroachdbError.js.map +1 -1
- package/dist/errors/index.d.ts +1 -0
- package/dist/errors/index.js +1 -0
- package/dist/errors/index.js.map +1 -1
- package/dist/errors/prismaError.d.ts +7 -0
- package/dist/errors/prismaError.js +9 -0
- package/dist/errors/prismaError.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/retry/calculateRetryDelay.d.ts +1 -0
- package/dist/retry/calculateRetryDelay.js +6 -0
- package/dist/retry/calculateRetryDelay.js.map +1 -0
- package/dist/retry/index.d.ts +2 -0
- package/dist/retry/index.js +2 -0
- package/dist/retry/index.js.map +1 -0
- package/dist/retry/retryOnSerializationFailure.d.ts +20 -0
- package/dist/retry/retryOnSerializationFailure.js +43 -0
- package/dist/retry/retryOnSerializationFailure.js.map +1 -0
- package/dist/retry/types.d.ts +5 -0
- package/dist/retry/types.js +2 -0
- package/dist/retry/types.js.map +1 -0
- package/dist/transaction/prismaTransaction.js +1 -5
- package/dist/transaction/prismaTransaction.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -143,6 +143,38 @@ errors, providing a robust and efficient way to ensure your transactions succeed
|
|
|
143
143
|
By automatically retrying failed transactions with an intelligent backoff strategy, you can significantly improve the
|
|
144
144
|
reliability and performance of your application when using distributed databases.
|
|
145
145
|
|
|
146
|
+
### Retry On Serialization Failure
|
|
147
|
+
|
|
148
|
+
Retries a single statement while it fails with a serialization failure, without opening a transaction around it.
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
import { retryOnSerializationFailure } from '@lokalise/prisma-utils'
|
|
152
|
+
|
|
153
|
+
const rows = await retryOnSerializationFailure(() =>
|
|
154
|
+
prisma.$queryRaw<Row[]>`SELECT ... FROM "segment" WHERE "project_id" = ${projectId}`,
|
|
155
|
+
)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Retries when the error is Prisma's `P2034` or a CockroachDB transaction retry error (SQLSTATE `40001`), in both the query-engine and the driver-adapter shape. Anything else is rethrown immediately, and the last error is rethrown once the retries are exhausted.
|
|
159
|
+
|
|
160
|
+
#### Options
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
const rows = await retryOnSerializationFailure(query, {
|
|
164
|
+
retriesAllowed: 2, // Default: 2 (total 3 attempts)
|
|
165
|
+
baseRetryDelayMs: 100, // Default: 100ms
|
|
166
|
+
maxRetryDelayMs: 30000, // Default: 30s
|
|
167
|
+
})
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The backoff is the same as `prismaTransaction`'s: `2^(retry-1) × baseRetryDelayMs`, capped at `maxRetryDelayMs`.
|
|
171
|
+
|
|
172
|
+
#### When To Use It Instead Of `prismaTransaction`
|
|
173
|
+
|
|
174
|
+
For a single read, wrapping the statement in an explicit transaction costs a BEGIN/COMMIT round trip and takes away CockroachDB's own ability to refresh and retry the implicit single-statement transaction server-side, which it can no longer do once the client has opened the transaction.
|
|
175
|
+
|
|
176
|
+
It is only safe around a **single read-only statement**. A write, or a statement that runs inside an interactive transaction, has to be retried at the transaction boundary (`prismaTransaction`) instead — replaying it alone would either duplicate its effects or re-run it against an aborted transaction.
|
|
177
|
+
|
|
146
178
|
### Prisma Bulk Update
|
|
147
179
|
|
|
148
180
|
Updates many rows in a single atomic SQL statement (`UPDATE ... FROM (VALUES ...)`), instead of issuing one `UPDATE` per row. Because it is a single statement, it either fully applies or fully rolls back, so no surrounding transaction is required. Works on both CockroachDB and PostgreSQL.
|
|
@@ -2,6 +2,11 @@ import type { PrismaClientKnownRequestError } from '@prisma/client/runtime/clien
|
|
|
2
2
|
/**
|
|
3
3
|
* Check if the error is a CockroachDB transaction retry error
|
|
4
4
|
*
|
|
5
|
+
* Two shapes carry the SQLSTATE, depending on how the query reached the database:
|
|
6
|
+
* - the Rust query engine reports it flat, as `meta.code`
|
|
7
|
+
* - a driver adapter (e.g. `@prisma/adapter-pg`) reports a `P2010` whose SQLSTATE is nested
|
|
8
|
+
* under `meta.driverAdapterError.cause.originalCode`, with no `meta.code` at all
|
|
9
|
+
*
|
|
5
10
|
* @param error
|
|
6
11
|
*/
|
|
7
12
|
export declare const isCockroachDBRetryTransaction: (error: PrismaClientKnownRequestError) => boolean;
|
|
@@ -4,15 +4,29 @@
|
|
|
4
4
|
* All transaction retry errors use the SQLSTATE error code 40001
|
|
5
5
|
*/
|
|
6
6
|
const COCKROACHDB_RETRY_TRANSACTION_CODE = '40001';
|
|
7
|
+
const isRecord = (value) => typeof value === 'object' && value !== null;
|
|
7
8
|
/**
|
|
8
9
|
* Check if the error is a CockroachDB transaction retry error
|
|
9
10
|
*
|
|
11
|
+
* Two shapes carry the SQLSTATE, depending on how the query reached the database:
|
|
12
|
+
* - the Rust query engine reports it flat, as `meta.code`
|
|
13
|
+
* - a driver adapter (e.g. `@prisma/adapter-pg`) reports a `P2010` whose SQLSTATE is nested
|
|
14
|
+
* under `meta.driverAdapterError.cause.originalCode`, with no `meta.code` at all
|
|
15
|
+
*
|
|
10
16
|
* @param error
|
|
11
17
|
*/
|
|
12
18
|
export const isCockroachDBRetryTransaction = (error) => {
|
|
13
19
|
const meta = error.meta;
|
|
14
|
-
if (!meta)
|
|
20
|
+
if (!isRecord(meta))
|
|
21
|
+
return false;
|
|
22
|
+
if (meta.code === COCKROACHDB_RETRY_TRANSACTION_CODE)
|
|
23
|
+
return true;
|
|
24
|
+
const driverAdapterError = meta.driverAdapterError;
|
|
25
|
+
if (!isRecord(driverAdapterError))
|
|
26
|
+
return false;
|
|
27
|
+
const cause = driverAdapterError.cause;
|
|
28
|
+
if (!isRecord(cause))
|
|
15
29
|
return false;
|
|
16
|
-
return
|
|
30
|
+
return cause.originalCode === COCKROACHDB_RETRY_TRANSACTION_CODE;
|
|
17
31
|
};
|
|
18
32
|
//# sourceMappingURL=cockroachdbError.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cockroachdbError.js","sourceRoot":"","sources":["../../src/errors/cockroachdbError.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,kCAAkC,GAAG,OAAO,CAAA;AAElD
|
|
1
|
+
{"version":3,"file":"cockroachdbError.js","sourceRoot":"","sources":["../../src/errors/cockroachdbError.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,kCAAkC,GAAG,OAAO,CAAA;AAElD,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAoC,EAAE,CACpE,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAA;AAE7C;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,KAAoC,EAAW,EAAE;IAC7F,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAA;IACvB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAA;IAEjC,IAAI,IAAI,CAAC,IAAI,KAAK,kCAAkC;QAAE,OAAO,IAAI,CAAA;IAEjE,MAAM,kBAAkB,GAAG,IAAI,CAAC,kBAAkB,CAAA;IAClD,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC;QAAE,OAAO,KAAK,CAAA;IAE/C,MAAM,KAAK,GAAG,kBAAkB,CAAC,KAAK,CAAA;IACtC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IAElC,OAAO,KAAK,CAAC,YAAY,KAAK,kCAAkC,CAAA;AAClE,CAAC,CAAA"}
|
package/dist/errors/index.d.ts
CHANGED
package/dist/errors/index.js
CHANGED
package/dist/errors/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAA;AACrC,cAAc,kBAAkB,CAAA"}
|
|
@@ -8,6 +8,13 @@ import type { PrismaClientKnownRequestError } from '@prisma/client/runtime/clien
|
|
|
8
8
|
*/
|
|
9
9
|
export declare const isPrismaClientKnownRequestError: (error: unknown) => error is PrismaClientKnownRequestError;
|
|
10
10
|
export declare const isPrismaTransactionClosedError: (error: PrismaClientKnownRequestError) => boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Check if the error is a serialization failure, and therefore safe to retry.
|
|
13
|
+
*
|
|
14
|
+
* Covers both Prisma's own `P2034` and the SQLSTATE 40001 reported by CockroachDB, whose shape
|
|
15
|
+
* depends on whether the query went through the Rust query engine or a driver adapter.
|
|
16
|
+
*/
|
|
17
|
+
export declare const isSerializationFailure: (error: unknown) => boolean;
|
|
11
18
|
/**
|
|
12
19
|
* Prisma error code P2025 indicates that the operation failed because it depends on one or more
|
|
13
20
|
* records that were required but not found
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isError } from '@lokalise/node-core';
|
|
2
|
+
import { isCockroachDBRetryTransaction } from './cockroachdbError.js';
|
|
2
3
|
/**
|
|
3
4
|
* What is checked?
|
|
4
5
|
* 1. error is defined and not null
|
|
@@ -13,6 +14,14 @@ export const isPrismaClientKnownRequestError = (error) => !!error &&
|
|
|
13
14
|
error.code.startsWith('P');
|
|
14
15
|
export const isPrismaTransactionClosedError = (error) => error.code === PRISMA_TRANSACTION_ERROR &&
|
|
15
16
|
error.message.toLowerCase().includes('transaction already closed');
|
|
17
|
+
/**
|
|
18
|
+
* Check if the error is a serialization failure, and therefore safe to retry.
|
|
19
|
+
*
|
|
20
|
+
* Covers both Prisma's own `P2034` and the SQLSTATE 40001 reported by CockroachDB, whose shape
|
|
21
|
+
* depends on whether the query went through the Rust query engine or a driver adapter.
|
|
22
|
+
*/
|
|
23
|
+
export const isSerializationFailure = (error) => isPrismaClientKnownRequestError(error) &&
|
|
24
|
+
(error.code === PRISMA_SERIALIZATION_ERROR || isCockroachDBRetryTransaction(error));
|
|
16
25
|
/**
|
|
17
26
|
* Prisma error code P2025 indicates that the operation failed because it depends on one or more
|
|
18
27
|
* records that were required but not found
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prismaError.js","sourceRoot":"","sources":["../../src/errors/prismaError.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"prismaError.js","sourceRoot":"","sources":["../../src/errors/prismaError.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAE7C,OAAO,EAAE,6BAA6B,EAAE,MAAM,uBAAuB,CAAA;AAErE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAC7C,KAAc,EAC0B,EAAE,CAC1C,CAAC,CAAC,KAAK;IACP,OAAO,CAAC,KAAK,CAAC;IACd,MAAM,IAAI,KAAK;IACf,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;IAC9B,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;AAE5B,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,KAAoC,EAAW,EAAE,CAC9F,KAAK,CAAC,IAAI,KAAK,wBAAwB;IACvC,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAA;AAEpE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,KAAc,EAAW,EAAE,CAChE,+BAA+B,CAAC,KAAK,CAAC;IACtC,CAAC,KAAK,CAAC,IAAI,KAAK,0BAA0B,IAAI,6BAA6B,CAAC,KAAK,CAAC,CAAC,CAAA;AAErF;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,OAAO,CAAA;AAE7C;;;;GAIG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,OAAO,CAAA;AAEjD;;;GAGG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,OAAO,CAAA;AAErD;;;GAGG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,OAAO,CAAA;AAE/C;;GAEG;AACH,MAAM,CAAC,MAAM,qCAAqC,GAAG,OAAO,CAAA"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAA;AACtC,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,cAAc,wBAAwB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAA;AACtC,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,cAAc,kBAAkB,CAAA;AAChC,cAAc,wBAAwB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const calculateRetryDelay: (retries: number, baseRetryDelayMs: number, maxDelayMs: number) => number;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export const calculateRetryDelay = (retries, baseRetryDelayMs, maxDelayMs) => {
|
|
2
|
+
// exponential backoff -> 2^(retry-1) * baseRetryDelayMs
|
|
3
|
+
const expDelay = Math.pow(2, retries - 1) * baseRetryDelayMs;
|
|
4
|
+
return Math.min(expDelay, maxDelayMs);
|
|
5
|
+
};
|
|
6
|
+
//# sourceMappingURL=calculateRetryDelay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calculateRetryDelay.js","sourceRoot":"","sources":["../../src/retry/calculateRetryDelay.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,OAAe,EACf,gBAAwB,EACxB,UAAkB,EACV,EAAE;IACV,wDAAwD;IACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,GAAG,gBAAgB,CAAA;IAC5D,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;AACvC,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/retry/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { RetryOnSerializationFailureOptions } from './types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Run a single statement, retrying it with exponential backoff while it fails with a
|
|
4
|
+
* serialization failure. Any other error is rethrown immediately, and the last serialization
|
|
5
|
+
* failure is rethrown once the retries are exhausted.
|
|
6
|
+
*
|
|
7
|
+
* Use this instead of {@link prismaTransaction} when the statement is a single read: wrapping one
|
|
8
|
+
* statement in an explicit transaction costs a BEGIN/COMMIT round trip and takes away
|
|
9
|
+
* CockroachDB's own ability to refresh and retry the implicit single-statement transaction
|
|
10
|
+
* server-side, which it can no longer do once the client has opened the transaction.
|
|
11
|
+
*
|
|
12
|
+
* Only safe around a single read-only statement. A write, or a statement that runs inside an
|
|
13
|
+
* interactive transaction, has to be retried at the transaction boundary instead - replaying it
|
|
14
|
+
* alone would either duplicate its effects or re-run it against an aborted transaction.
|
|
15
|
+
*
|
|
16
|
+
* @param {() => Promise<T>} query function issuing the statement, called once per attempt
|
|
17
|
+
* @param {RetryOnSerializationFailureOptions} options retry configuration
|
|
18
|
+
* @return {Promise<T>}
|
|
19
|
+
*/
|
|
20
|
+
export declare const retryOnSerializationFailure: <T>(query: () => Promise<T>, options?: RetryOnSerializationFailureOptions) => Promise<T>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { setTimeout } from 'node:timers/promises';
|
|
2
|
+
import { isSerializationFailure } from '../errors/index.js';
|
|
3
|
+
import { calculateRetryDelay } from './calculateRetryDelay.js';
|
|
4
|
+
const DEFAULT_OPTIONS = {
|
|
5
|
+
retriesAllowed: 2, // first try + 2 retries = 3 tries
|
|
6
|
+
baseRetryDelayMs: 100,
|
|
7
|
+
maxRetryDelayMs: 30000, // 30s
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Run a single statement, retrying it with exponential backoff while it fails with a
|
|
11
|
+
* serialization failure. Any other error is rethrown immediately, and the last serialization
|
|
12
|
+
* failure is rethrown once the retries are exhausted.
|
|
13
|
+
*
|
|
14
|
+
* Use this instead of {@link prismaTransaction} when the statement is a single read: wrapping one
|
|
15
|
+
* statement in an explicit transaction costs a BEGIN/COMMIT round trip and takes away
|
|
16
|
+
* CockroachDB's own ability to refresh and retry the implicit single-statement transaction
|
|
17
|
+
* server-side, which it can no longer do once the client has opened the transaction.
|
|
18
|
+
*
|
|
19
|
+
* Only safe around a single read-only statement. A write, or a statement that runs inside an
|
|
20
|
+
* interactive transaction, has to be retried at the transaction boundary instead - replaying it
|
|
21
|
+
* alone would either duplicate its effects or re-run it against an aborted transaction.
|
|
22
|
+
*
|
|
23
|
+
* @param {() => Promise<T>} query function issuing the statement, called once per attempt
|
|
24
|
+
* @param {RetryOnSerializationFailureOptions} options retry configuration
|
|
25
|
+
* @return {Promise<T>}
|
|
26
|
+
*/
|
|
27
|
+
export const retryOnSerializationFailure = async (query, options) => {
|
|
28
|
+
// resolved per option, as spreading `options` would let an explicit `undefined` erase a default
|
|
29
|
+
const retriesAllowed = options?.retriesAllowed ?? DEFAULT_OPTIONS.retriesAllowed;
|
|
30
|
+
const baseRetryDelayMs = options?.baseRetryDelayMs ?? DEFAULT_OPTIONS.baseRetryDelayMs;
|
|
31
|
+
const maxRetryDelayMs = options?.maxRetryDelayMs ?? DEFAULT_OPTIONS.maxRetryDelayMs;
|
|
32
|
+
for (let retries = 0;; retries++) {
|
|
33
|
+
try {
|
|
34
|
+
return await query();
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
if (retries >= retriesAllowed || !isSerializationFailure(error))
|
|
38
|
+
throw error;
|
|
39
|
+
await setTimeout(calculateRetryDelay(retries + 1, baseRetryDelayMs, maxRetryDelayMs));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=retryOnSerializationFailure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retryOnSerializationFailure.js","sourceRoot":"","sources":["../../src/retry/retryOnSerializationFailure.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAG9D,MAAM,eAAe,GAAG;IACtB,cAAc,EAAE,CAAC,EAAE,kCAAkC;IACrD,gBAAgB,EAAE,GAAG;IACrB,eAAe,EAAE,KAAK,EAAE,MAAM;CACwB,CAAA;AAExD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,KAAK,EAC9C,KAAuB,EACvB,OAA4C,EAChC,EAAE;IACd,gGAAgG;IAChG,MAAM,cAAc,GAAG,OAAO,EAAE,cAAc,IAAI,eAAe,CAAC,cAAc,CAAA;IAChF,MAAM,gBAAgB,GAAG,OAAO,EAAE,gBAAgB,IAAI,eAAe,CAAC,gBAAgB,CAAA;IACtF,MAAM,eAAe,GAAG,OAAO,EAAE,eAAe,IAAI,eAAe,CAAC,eAAe,CAAA;IAEnF,KAAK,IAAI,OAAO,GAAG,CAAC,GAAI,OAAO,EAAE,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,OAAO,MAAM,KAAK,EAAE,CAAA;QACtB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,OAAO,IAAI,cAAc,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC;gBAAE,MAAM,KAAK,CAAA;YAC5E,MAAM,UAAU,CAAC,mBAAmB,CAAC,OAAO,GAAG,CAAC,EAAE,gBAAgB,EAAE,eAAe,CAAC,CAAC,CAAA;QACvF,CAAC;IACH,CAAC;AACH,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/retry/types.ts"],"names":[],"mappings":""}
|
|
@@ -2,6 +2,7 @@ import { setTimeout } from 'node:timers/promises';
|
|
|
2
2
|
import { deepClone } from '@lokalise/node-core';
|
|
3
3
|
import { isCockroachDBRetryTransaction } from '../errors/cockroachdbError.js';
|
|
4
4
|
import { isPrismaClientKnownRequestError, isPrismaTransactionClosedError, PRISMA_SERIALIZATION_ERROR, PRISMA_SERVER_CLOSED_CONNECTION_ERROR, PRISMA_TRANSACTION_ERROR, } from '../errors/index.js';
|
|
5
|
+
import { calculateRetryDelay } from '../retry/calculateRetryDelay.js';
|
|
5
6
|
const DEFAULT_OPTIONS = {
|
|
6
7
|
retriesAllowed: 2, // first try + 2 retries = 3 tries
|
|
7
8
|
baseRetryDelayMs: 100,
|
|
@@ -51,11 +52,6 @@ const executeTransactionTry = async (prisma, arg, options) => {
|
|
|
51
52
|
return { error };
|
|
52
53
|
}
|
|
53
54
|
};
|
|
54
|
-
const calculateRetryDelay = (retries, baseRetryDelayMs, maxDelayMs) => {
|
|
55
|
-
// exponential backoff -> 2^(retry-1) * baseRetryDelayMs
|
|
56
|
-
const expDelay = Math.pow(2, retries - 1) * baseRetryDelayMs;
|
|
57
|
-
return Math.min(expDelay, maxDelayMs);
|
|
58
|
-
};
|
|
59
55
|
const PrismaCodesToRetry = [
|
|
60
56
|
PRISMA_SERIALIZATION_ERROR,
|
|
61
57
|
PRISMA_SERVER_CLOSED_CONNECTION_ERROR,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prismaTransaction.js","sourceRoot":"","sources":["../../src/transaction/prismaTransaction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAEjD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAG/C,OAAO,EAAE,6BAA6B,EAAE,MAAM,+BAA+B,CAAA;AAC7E,OAAO,EACL,+BAA+B,EAC/B,8BAA8B,EAC9B,0BAA0B,EAC1B,qCAAqC,EACrC,wBAAwB,GACzB,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"prismaTransaction.js","sourceRoot":"","sources":["../../src/transaction/prismaTransaction.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lokalise/prisma-utils",
|
|
3
|
-
"version": "7.0
|
|
3
|
+
"version": "7.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"files": [
|
|
@@ -27,10 +27,10 @@
|
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@biomejs/biome": "^2.5.12",
|
|
30
|
-
"dotenv": "^
|
|
31
|
-
"@lokalise/biome-config": "^
|
|
30
|
+
"dotenv": "^18.0.8",
|
|
31
|
+
"@lokalise/biome-config": "^4.0.0",
|
|
32
32
|
"@lokalise/tsconfig": "^5.0.0",
|
|
33
|
-
"@prisma/adapter-pg": "^7.
|
|
33
|
+
"@prisma/adapter-pg": "^7.10.1",
|
|
34
34
|
"@prisma/client": "^7.10.0",
|
|
35
35
|
"@vitest/coverage-v8": "^4.1.11",
|
|
36
36
|
"cross-env": "^10.0.0",
|