@lokalise/prisma-utils 5.0.2 → 6.0.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/README.md +129 -12
- package/dist/errors/cockroachdbError.d.ts +1 -1
- package/dist/errors/prismaError.d.ts +1 -1
- package/dist/factory/extendPrismaClientWithMetrics.d.ts +3 -0
- package/dist/factory/extendPrismaClientWithMetrics.js +90 -0
- package/dist/factory/extendPrismaClientWithMetrics.js.map +1 -0
- package/dist/factory/index.d.ts +1 -0
- package/dist/factory/index.js +2 -0
- package/dist/factory/index.js.map +1 -0
- package/dist/factory/prismaClientFactory.d.ts +20 -0
- package/dist/factory/prismaClientFactory.js +26 -0
- package/dist/factory/prismaClientFactory.js.map +1 -0
- package/dist/index.d.ts +2 -3
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/dist/transaction/index.d.ts +2 -0
- package/dist/transaction/index.js +2 -0
- package/dist/transaction/index.js.map +1 -0
- package/dist/transaction/prismaTransaction.d.ts +17 -0
- package/dist/{prismaTransaction.js → transaction/prismaTransaction.js} +5 -6
- package/dist/transaction/prismaTransaction.js.map +1 -0
- package/dist/transaction/types.d.ts +15 -0
- package/dist/transaction/types.js +2 -0
- package/dist/transaction/types.js.map +1 -0
- package/dist/types.d.ts +2 -39
- package/dist/types.js +2 -1
- package/dist/types.js.map +1 -1
- package/package.json +13 -18
- package/dist/isolation_level/isolationLevel.d.ts +0 -3
- package/dist/isolation_level/isolationLevel.js +0 -2
- package/dist/isolation_level/isolationLevel.js.map +0 -1
- package/dist/plugins/CollectionScheduler.d.ts +0 -12
- package/dist/plugins/CollectionScheduler.js +0 -20
- package/dist/plugins/CollectionScheduler.js.map +0 -1
- package/dist/plugins/MetricsCollector.d.ts +0 -36
- package/dist/plugins/MetricsCollector.js +0 -188
- package/dist/plugins/MetricsCollector.js.map +0 -1
- package/dist/plugins/prismaMetricsPlugin.d.ts +0 -21
- package/dist/plugins/prismaMetricsPlugin.js +0 -49
- package/dist/plugins/prismaMetricsPlugin.js.map +0 -1
- package/dist/prismaClientFactory.d.ts +0 -5
- package/dist/prismaClientFactory.js +0 -11
- package/dist/prismaClientFactory.js.map +0 -1
- package/dist/prismaTransaction.d.ts +0 -17
- package/dist/prismaTransaction.js.map +0 -1
package/README.md
CHANGED
|
@@ -2,26 +2,143 @@
|
|
|
2
2
|
|
|
3
3
|
This package provides reusable helpers for Prisma query builder.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @lokalise/prisma-utils
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
### Prisma Client Factory
|
|
14
|
+
|
|
15
|
+
Factory function to create a Prisma client instance with default configuration and optional Prometheus metrics integration.
|
|
16
|
+
|
|
17
|
+
**Without metrics:**
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { prismaClientFactory } from '@lokalise/prisma-utils'
|
|
21
|
+
import { PrismaClient } from '@prisma/client'
|
|
22
|
+
|
|
23
|
+
const prisma = prismaClientFactory(PrismaClient, {
|
|
24
|
+
// Your Prisma client options
|
|
25
|
+
})
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**With Prometheus metrics:**
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { prismaClientFactory } from '@lokalise/prisma-utils'
|
|
32
|
+
import { PrismaClient } from '@prisma/client'
|
|
33
|
+
import * as promClient from 'prom-client'
|
|
34
|
+
|
|
35
|
+
const prisma = prismaClientFactory(
|
|
36
|
+
PrismaClient,
|
|
37
|
+
{
|
|
38
|
+
// Your Prisma client options
|
|
39
|
+
},
|
|
40
|
+
{ promClient }
|
|
41
|
+
)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The factory automatically:
|
|
45
|
+
- Sets default transaction isolation level to `ReadCommitted`
|
|
46
|
+
- Extends the client with Prometheus metrics when `promClient` is provided
|
|
47
|
+
|
|
48
|
+
#### Prisma Metrics Collection
|
|
49
|
+
|
|
50
|
+
When you provide `promClient` to the factory, the following metrics are automatically collected:
|
|
51
|
+
|
|
52
|
+
- **`prisma_queries_total`**: Total number of Prisma queries executed
|
|
53
|
+
- Labels: `model`, `operation`, `status` (success/error)
|
|
54
|
+
- **`prisma_query_duration_seconds`**: Duration of Prisma queries in seconds
|
|
55
|
+
- Labels: `model`, `operation`
|
|
56
|
+
- Buckets: [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5]
|
|
57
|
+
- **`prisma_errors_total`**: Total number of Prisma query errors
|
|
58
|
+
- Labels: `model`, `operation`, `error_code`
|
|
59
|
+
|
|
60
|
+
These metrics are automatically exposed through the Prometheus registry and can be scraped by your monitoring system.
|
|
61
|
+
|
|
62
|
+
### Prisma Transactions
|
|
63
|
+
|
|
64
|
+
Helper for executing Prisma transactions with intelligent automatic retry mechanism, optimized for distributed databases like CockroachDB.
|
|
65
|
+
|
|
66
|
+
#### Basic Usage
|
|
67
|
+
|
|
68
|
+
**With multiple operations:**
|
|
6
69
|
|
|
7
70
|
```typescript
|
|
8
71
|
import { prismaTransaction } from '@lokalise/prisma-utils'
|
|
72
|
+
import type { Either } from '@lokalise/node-core'
|
|
9
73
|
|
|
10
|
-
const result: Either<unknown, [Item, Segment]> = await prismaTransaction(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
74
|
+
const result: Either<unknown, [Item, Segment]> = await prismaTransaction(
|
|
75
|
+
prisma,
|
|
76
|
+
{ dbDriver: 'CockroachDb' },
|
|
77
|
+
[
|
|
78
|
+
prisma.item.create({ data: { value: 'item-1' } }),
|
|
79
|
+
prisma.segment.create({ data: { name: 'segment-1' } }),
|
|
80
|
+
]
|
|
81
|
+
)
|
|
14
82
|
```
|
|
15
83
|
|
|
16
|
-
|
|
84
|
+
**With transaction callback:**
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
const result: Either<unknown, User> = await prismaTransaction(
|
|
88
|
+
prisma,
|
|
89
|
+
{ dbDriver: 'CockroachDb' },
|
|
90
|
+
async (tx) => {
|
|
91
|
+
const user = await tx.user.create({ data: { name: 'John' } })
|
|
92
|
+
await tx.profile.create({ data: { userId: user.id, bio: 'Developer' } })
|
|
93
|
+
return user
|
|
94
|
+
}
|
|
95
|
+
)
|
|
96
|
+
```
|
|
17
97
|
|
|
18
|
-
|
|
98
|
+
#### Automatic Retry Mechanism
|
|
19
99
|
|
|
20
|
-
|
|
100
|
+
The transaction helper automatically retries on the following error conditions:
|
|
21
101
|
|
|
22
|
-
|
|
102
|
+
**Prisma Error Codes:**
|
|
103
|
+
- **P2034**: Write conflict / Serialization failure (common in distributed databases)
|
|
104
|
+
- **P2028**: Transaction API error
|
|
105
|
+
- **P1017**: Server closed the connection
|
|
106
|
+
|
|
107
|
+
**CockroachDB-specific:**
|
|
108
|
+
- Automatically detects and retries CockroachDB retry transaction errors.
|
|
109
|
+
|
|
110
|
+
#### Retry Strategy
|
|
111
|
+
|
|
112
|
+
1. **Exponential Backoff**: Delay between retries increases exponentially
|
|
113
|
+
- Formula: `2^(retry-1) × baseRetryDelayMs`
|
|
114
|
+
- Example: 100ms → 200ms → 400ms → 800ms...
|
|
115
|
+
|
|
116
|
+
2. **Smart Timeout Adjustment**: If transaction times out (P2028 with "transaction is closed"), the timeout is
|
|
117
|
+
automatically doubled on retry (up to `maxTimeout`)
|
|
118
|
+
|
|
119
|
+
3. **Configurable Options**:
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
const result = await prismaTransaction(
|
|
123
|
+
prisma,
|
|
124
|
+
{
|
|
125
|
+
dbDriver: 'CockroachDb', // Enable CockroachDB-specific retries
|
|
126
|
+
retriesAllowed: 2, // Default: 2 (total 3 attempts)
|
|
127
|
+
baseRetryDelayMs: 100, // Default: 100ms
|
|
128
|
+
maxRetryDelayMs: 30000, // Default: 30s (max delay between retries)
|
|
129
|
+
timeout: 5000, // Default: 5s (transaction timeout)
|
|
130
|
+
maxTimeout: 30000, // Default: 30s (max transaction timeout)
|
|
131
|
+
},
|
|
132
|
+
[
|
|
133
|
+
// Your transaction operations
|
|
134
|
+
]
|
|
135
|
+
)
|
|
136
|
+
```
|
|
23
137
|
|
|
24
|
-
|
|
25
|
-
- `collectionOptions` (by default we collect metrics `every 5 seconds`) to override default collector behaviour
|
|
138
|
+
#### Why This Matters
|
|
26
139
|
|
|
27
|
-
|
|
140
|
+
Distributed databases like CockroachDB use optimistic concurrency control, which can result in serialization errors
|
|
141
|
+
when multiple transactions compete for the same resources. This helper abstracts away the complexity of handling these
|
|
142
|
+
errors, providing a robust and efficient way to ensure your transactions succeed even under high contention.
|
|
143
|
+
By automatically retrying failed transactions with an intelligent backoff strategy, you can significantly improve the
|
|
144
|
+
reliability and performance of your application when using distributed databases.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
export const extendPrismaClientWithMetrics = (prisma, promClient) => createExtendedClient(prisma, registerMetricsIfNeeded(promClient));
|
|
2
|
+
const METRICS_PREFIX = 'prisma';
|
|
3
|
+
const createExtendedClient = (prisma, metrics) => {
|
|
4
|
+
return prisma.$extends({
|
|
5
|
+
name: 'metrics-collector',
|
|
6
|
+
query: {
|
|
7
|
+
$allModels: {
|
|
8
|
+
async $allOperations({ model, operation, args, query }) {
|
|
9
|
+
const startTime = Date.now();
|
|
10
|
+
const resolvedModel = model ?? 'unknown';
|
|
11
|
+
let result = { result: undefined };
|
|
12
|
+
try {
|
|
13
|
+
const response = await query(args);
|
|
14
|
+
result = { result: response };
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
result = { error };
|
|
18
|
+
}
|
|
19
|
+
finally {
|
|
20
|
+
const duration = (Date.now() - startTime) / 1000;
|
|
21
|
+
// Always record metrics (success or error)
|
|
22
|
+
metrics.queriesTotal.inc({
|
|
23
|
+
model: resolvedModel,
|
|
24
|
+
operation,
|
|
25
|
+
status: result.error ? 'error' : 'success',
|
|
26
|
+
});
|
|
27
|
+
metrics.queryDuration.observe({ model: resolvedModel, operation }, duration);
|
|
28
|
+
if (result.error) {
|
|
29
|
+
const errorCode = result.error?.code || 'unknown';
|
|
30
|
+
metrics.errorsTotal.inc({
|
|
31
|
+
model: resolvedModel,
|
|
32
|
+
operation,
|
|
33
|
+
error_code: errorCode,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (result.error)
|
|
38
|
+
throw result.error;
|
|
39
|
+
return result.result;
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Register Prometheus metrics if they don't already exist
|
|
47
|
+
*/
|
|
48
|
+
const registerMetricsIfNeeded = (promClient) => {
|
|
49
|
+
const existingMetrics = getExistingMetrics(promClient);
|
|
50
|
+
if (existingMetrics)
|
|
51
|
+
return existingMetrics;
|
|
52
|
+
const queriesTotal = new promClient.Counter({
|
|
53
|
+
name: `${METRICS_PREFIX}_queries_total`,
|
|
54
|
+
help: 'Total number of Prisma queries executed',
|
|
55
|
+
labelNames: ['model', 'operation', 'status'],
|
|
56
|
+
registers: [promClient.register],
|
|
57
|
+
});
|
|
58
|
+
const queryDuration = new promClient.Histogram({
|
|
59
|
+
name: `${METRICS_PREFIX}_query_duration_seconds`,
|
|
60
|
+
help: 'Duration of Prisma queries in seconds',
|
|
61
|
+
labelNames: ['model', 'operation'],
|
|
62
|
+
buckets: [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5],
|
|
63
|
+
registers: [promClient.register],
|
|
64
|
+
});
|
|
65
|
+
const errorsTotal = new promClient.Counter({
|
|
66
|
+
name: `${METRICS_PREFIX}_errors_total`,
|
|
67
|
+
help: 'Total number of Prisma query errors',
|
|
68
|
+
labelNames: ['model', 'operation', 'error_code'],
|
|
69
|
+
registers: [promClient.register],
|
|
70
|
+
});
|
|
71
|
+
return { queriesTotal, queryDuration, errorsTotal };
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Check if metrics already exist in the registry
|
|
75
|
+
*/
|
|
76
|
+
const getExistingMetrics = (promClient) => {
|
|
77
|
+
try {
|
|
78
|
+
const queriesTotal = promClient.register.getSingleMetric(`${METRICS_PREFIX}_queries_total`);
|
|
79
|
+
const queryDuration = promClient.register.getSingleMetric(`${METRICS_PREFIX}_query_duration_seconds`);
|
|
80
|
+
const errorsTotal = promClient.register.getSingleMetric(`${METRICS_PREFIX}_errors_total`);
|
|
81
|
+
if (queriesTotal && queryDuration && errorsTotal) {
|
|
82
|
+
return { queriesTotal, queryDuration, errorsTotal };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// If any error occurs (e.g. metrics not found), return null to create new metrics
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
};
|
|
90
|
+
//# sourceMappingURL=extendPrismaClientWithMetrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extendPrismaClientWithMetrics.js","sourceRoot":"","sources":["../../src/factory/extendPrismaClientWithMetrics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { prismaClientFactory } from './prismaClientFactory.ts';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/factory/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type * as RuntimePrisma from '@prisma/client/runtime/client';
|
|
2
|
+
import type { PrismaClient } from 'db-client/client.ts';
|
|
3
|
+
import type { PrismaClientConstructor } from 'db-client/internal/class.ts';
|
|
4
|
+
import type Prometheus from 'prom-client';
|
|
5
|
+
export type prismaClientFactoryOptions = {
|
|
6
|
+
promClient?: typeof Prometheus;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Factory function to create a Prisma client instance with default configuration
|
|
10
|
+
* and optional Prometheus metrics integration.
|
|
11
|
+
*
|
|
12
|
+
* @template Client - The Prisma client type to instantiate
|
|
13
|
+
* @param builder - The Prisma client constructor
|
|
14
|
+
* @param options - Prisma client initialization options
|
|
15
|
+
* @param factoryOptions - Optional factory configuration
|
|
16
|
+
* @param factoryOptions.promClient - Prometheus client instance to enable metrics collection
|
|
17
|
+
* @returns A configured Prisma client instance, optionally extended with metrics
|
|
18
|
+
*
|
|
19
|
+
*/
|
|
20
|
+
export declare const prismaClientFactory: <Client extends PrismaClient>(builder: PrismaClientConstructor, options: RuntimePrisma.PrismaClientOptions, factoryOptions?: prismaClientFactoryOptions) => Client;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { extendPrismaClientWithMetrics } from "./extendPrismaClientWithMetrics.js";
|
|
2
|
+
/**
|
|
3
|
+
* Factory function to create a Prisma client instance with default configuration
|
|
4
|
+
* and optional Prometheus metrics integration.
|
|
5
|
+
*
|
|
6
|
+
* @template Client - The Prisma client type to instantiate
|
|
7
|
+
* @param builder - The Prisma client constructor
|
|
8
|
+
* @param options - Prisma client initialization options
|
|
9
|
+
* @param factoryOptions - Optional factory configuration
|
|
10
|
+
* @param factoryOptions.promClient - Prometheus client instance to enable metrics collection
|
|
11
|
+
* @returns A configured Prisma client instance, optionally extended with metrics
|
|
12
|
+
*
|
|
13
|
+
*/
|
|
14
|
+
export const prismaClientFactory = (builder, options, factoryOptions) => {
|
|
15
|
+
options.transactionOptions = {
|
|
16
|
+
isolationLevel: 'ReadCommitted',
|
|
17
|
+
...options.transactionOptions,
|
|
18
|
+
};
|
|
19
|
+
// @ts-expect-error
|
|
20
|
+
let prismaClient = new builder(options);
|
|
21
|
+
if (factoryOptions?.promClient) {
|
|
22
|
+
prismaClient = extendPrismaClientWithMetrics(prismaClient, factoryOptions.promClient);
|
|
23
|
+
}
|
|
24
|
+
return prismaClient;
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=prismaClientFactory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prismaClientFactory.js","sourceRoot":"","sources":["../../src/factory/prismaClientFactory.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAA;AAMlF;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,OAAgC,EAChC,OAA0C,EAC1C,cAA2C,EACnC,EAAE;IACV,OAAO,CAAC,kBAAkB,GAAG;QAC3B,cAAc,EAAE,eAAe;QAC/B,GAAG,OAAO,CAAC,kBAAkB;KAC9B,CAAA;IAED,mBAAmB;IACnB,IAAI,YAAY,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,CAAA;IACvC,IAAI,cAAc,EAAE,UAAU,EAAE,CAAC;QAC/B,YAAY,GAAG,6BAA6B,CAAC,YAAY,EAAE,cAAc,CAAC,UAAU,CAAC,CAAA;IACvF,CAAC;IAED,OAAO,YAAsB,CAAA;AAC/B,CAAC,CAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export * from './errors/index.ts';
|
|
2
|
-
export
|
|
3
|
-
export
|
|
4
|
-
export { prismaTransaction } from './prismaTransaction.ts';
|
|
2
|
+
export * from './factory/index.ts';
|
|
3
|
+
export * from './transaction/index.ts';
|
|
5
4
|
export type * from './types.ts';
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export * from "./errors/index.js";
|
|
2
|
-
export
|
|
3
|
-
export
|
|
4
|
-
export { prismaTransaction } from "./prismaTransaction.js";
|
|
2
|
+
export * from "./factory/index.js";
|
|
3
|
+
export * from "./transaction/index.js";
|
|
5
4
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAA;AACjC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,cAAc,wBAAwB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transaction/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Either } from '@lokalise/node-core';
|
|
2
|
+
import type * as RuntimePrisma from '@prisma/client/runtime/client';
|
|
3
|
+
import type { PrismaClient } from 'db-client/client.ts';
|
|
4
|
+
import type { PrismaTransactionFn, PrismaTransactionOptions } from './types.ts';
|
|
5
|
+
/**
|
|
6
|
+
* Perform a Prisma DB transaction with automatic retries if needed.
|
|
7
|
+
*
|
|
8
|
+
* @template T | T extends Prisma.PrismaPromise<unknown>[]
|
|
9
|
+
* @param {PrismaClient} prisma
|
|
10
|
+
* @param {PrismaTransactionFn<T> | RuntimePrisma.PrismaPromise<unknown>[]} arg operation to perform into the transaction
|
|
11
|
+
* @param {PrismaTransactionOptions} options transaction configuration
|
|
12
|
+
* @return {Promise<PrismaTransactionReturnType<T>>}
|
|
13
|
+
*/
|
|
14
|
+
export declare const prismaTransaction: {
|
|
15
|
+
<T, P extends PrismaClient>(prisma: P, options: PrismaTransactionOptions, fn: PrismaTransactionFn<T, P>): Promise<Either<unknown, T>>;
|
|
16
|
+
<T extends RuntimePrisma.PrismaPromise<unknown>[], P extends PrismaClient>(prisma: P, options: PrismaTransactionOptions, args: [...T]): Promise<Either<unknown, RuntimePrisma.Types.Utils.UnwrapTuple<T>>>;
|
|
17
|
+
};
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { setTimeout } from 'node:timers/promises';
|
|
2
2
|
import { deepClone } from '@lokalise/node-core';
|
|
3
|
-
import { isCockroachDBRetryTransaction } from "
|
|
4
|
-
import { isPrismaClientKnownRequestError, isPrismaTransactionClosedError, PRISMA_SERIALIZATION_ERROR, PRISMA_SERVER_CLOSED_CONNECTION_ERROR, PRISMA_TRANSACTION_ERROR, } from "
|
|
3
|
+
import { isCockroachDBRetryTransaction } from "../errors/cockroachdbError.js";
|
|
4
|
+
import { isPrismaClientKnownRequestError, isPrismaTransactionClosedError, PRISMA_SERIALIZATION_ERROR, PRISMA_SERVER_CLOSED_CONNECTION_ERROR, PRISMA_TRANSACTION_ERROR, } from "../errors/index.js";
|
|
5
5
|
const DEFAULT_OPTIONS = {
|
|
6
6
|
retriesAllowed: 2, // first try + 2 retries = 3 tries
|
|
7
|
-
dbDriver: 'CockroachDb',
|
|
8
7
|
baseRetryDelayMs: 100,
|
|
9
8
|
maxRetryDelayMs: 30000, // 30s
|
|
10
9
|
timeout: 5000, // 5s
|
|
@@ -15,11 +14,11 @@ const DEFAULT_OPTIONS = {
|
|
|
15
14
|
*
|
|
16
15
|
* @template T | T extends Prisma.PrismaPromise<unknown>[]
|
|
17
16
|
* @param {PrismaClient} prisma
|
|
18
|
-
* @param {PrismaTransactionFn<T> |
|
|
19
|
-
* @param {PrismaTransactionOptions
|
|
17
|
+
* @param {PrismaTransactionFn<T> | RuntimePrisma.PrismaPromise<unknown>[]} arg operation to perform into the transaction
|
|
18
|
+
* @param {PrismaTransactionOptions} options transaction configuration
|
|
20
19
|
* @return {Promise<PrismaTransactionReturnType<T>>}
|
|
21
20
|
*/
|
|
22
|
-
export const prismaTransaction = (async (prisma,
|
|
21
|
+
export const prismaTransaction = (async (prisma, options, arg) => {
|
|
23
22
|
let optionsWithDefaults = { ...DEFAULT_OPTIONS, ...options };
|
|
24
23
|
let result;
|
|
25
24
|
let retries = 0;
|
|
@@ -0,0 +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;AAQ3B,MAAM,eAAe,GAAG;IACtB,cAAc,EAAE,CAAC,EAAE,kCAAkC;IACrD,gBAAgB,EAAE,GAAG;IACrB,eAAe,EAAE,KAAK,EAAE,MAAM;IAC9B,OAAO,EAAE,IAAI,EAAE,KAAK;IACpB,UAAU,EAAE,KAAK,EAAE,MAAM;CACkB,CAAA;AAE7C;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAK,EACrC,MAAS,EACT,OAAiC,EACjC,GAAuE,EAC9B,EAAE;IAC3C,IAAI,mBAAmB,GAAG,EAAE,GAAG,eAAe,EAAE,GAAG,OAAO,EAAE,CAAA;IAC5D,IAAI,MAAkD,CAAA;IAEtD,IAAI,OAAO,GAAG,CAAC,CAAA;IACf,GAAG,CAAC;QACF,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAChB,MAAM,UAAU,CACd,mBAAmB,CACjB,OAAO,EACP,mBAAmB,CAAC,gBAAgB,EACpC,mBAAmB,CAAC,eAAe,CACpC,CACF,CAAA;QACH,CAAC;QAED,MAAM,GAAG,MAAM,qBAAqB,CAAC,MAAM,EAAE,GAAG,EAAE,mBAAmB,CAAC,CAAA;QACtE,IAAI,MAAM,CAAC,MAAM;YAAE,MAAK;QAExB,MAAM,YAAY,GAAG,cAAc,CAAC,MAAM,EAAE,mBAAmB,CAAC,QAAQ,CAAC,CAAA;QACzE,IAAI,CAAC,YAAY;YAAE,MAAK;QAExB,IAAI,YAAY,KAAK,kBAAkB,EAAE,CAAC;YACxC,mBAAmB,GAAG,SAAS,CAAC,mBAAmB,CAAC,CAAA;YACpD,mBAAmB,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CACpC,mBAAmB,CAAC,OAAO,GAAG,CAAC,EAC/B,mBAAmB,CAAC,UAAU,CAC/B,CAAA;QACH,CAAC;QAED,OAAO,EAAE,CAAA;IACX,CAAC,QAAQ,OAAO,IAAI,mBAAmB,CAAC,cAAc,EAAC;IAEvD,OAAO,MAAM,IAAI,EAAE,KAAK,EAAE,IAAI,KAAK,CAAC,yBAAyB,CAAC,EAAE,CAAA;AAClE,CAAC,CAWA,CAAA;AAED,MAAM,qBAAqB,GAAG,KAAK,EACjC,MAAS,EACT,GAAuE,EACvE,OAAkC,EACO,EAAE;IAC3C,IAAI,CAAC;QACH,OAAO;YACL,mBAAmB;YACnB,MAAM,EAAE,MAAM,MAAM,CAAC,YAAY,CAAI,GAAG,EAAE,OAAO,CAAC;SACnD,CAAA;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,KAAK,EAAE,CAAA;IAClB,CAAC;AACH,CAAC,CAAA;AAED,MAAM,mBAAmB,GAAG,CAC1B,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;AAED,MAAM,kBAAkB,GAAG;IACzB,0BAA0B;IAC1B,qCAAqC;IACrC,wBAAwB;CACzB,CAAA;AAGD,MAAM,cAAc,GAAG,CACrB,MAAsC,EACtC,QAAkB,EACI,EAAE;IACxB,IAAI,+BAA+B,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAClD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAA;QAC1B,wEAAwE;QACxE,8GAA8G;QAC9G,IAAI,8BAA8B,CAAC,KAAK,CAAC;YAAE,OAAO,kBAAkB,CAAA;QACpE,2DAA2D;QAC3D,IAAI,kBAAkB,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAA;QACxD,8DAA8D;QAC9D,IAAI,QAAQ,KAAK,aAAa,IAAI,6BAA6B,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAA;IACrF,CAAC;IAED,OAAO,KAAK,CAAA;AACd,CAAC,CAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Either } from '@lokalise/node-core';
|
|
2
|
+
import type * as RuntimePrisma from '@prisma/client/runtime/client';
|
|
3
|
+
import type { DbDriver } from '../types.ts';
|
|
4
|
+
type InternalTransactionOptions = RuntimePrisma.PrismaClientOptions['transactionOptions'];
|
|
5
|
+
export type PrismaTransactionOptions = {
|
|
6
|
+
dbDriver: DbDriver;
|
|
7
|
+
retriesAllowed?: number;
|
|
8
|
+
baseRetryDelayMs?: number;
|
|
9
|
+
maxRetryDelayMs?: number;
|
|
10
|
+
maxTimeout?: number;
|
|
11
|
+
} & InternalTransactionOptions;
|
|
12
|
+
export type PrismaTransactionClient<P> = Omit<P, RuntimePrisma.ITXClientDenyList>;
|
|
13
|
+
export type PrismaTransactionFn<T, P> = (prisma: PrismaTransactionClient<P>) => Promise<T>;
|
|
14
|
+
export type PrismaTransactionReturnType<T> = Either<unknown, T | RuntimePrisma.Types.Utils.UnwrapTuple<RuntimePrisma.PrismaPromise<unknown>[]>>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/transaction/types.ts"],"names":[],"mappings":""}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,44 +1,7 @@
|
|
|
1
|
-
import type { Either } from '@lokalise/node-core';
|
|
2
|
-
import type { Prisma } from '@prisma/client';
|
|
3
|
-
import type * as runtime from '@prisma/client/runtime/library';
|
|
4
|
-
import type { CockroachDbIsolationLevel } from './isolation_level/isolationLevel.ts';
|
|
5
1
|
type ObjectValues<T> = T[keyof T];
|
|
6
2
|
export declare const DbDriverEnum: {
|
|
7
|
-
readonly
|
|
3
|
+
readonly COCKROACH_DB: "CockroachDb";
|
|
4
|
+
readonly POSTGRES: "Postgres";
|
|
8
5
|
};
|
|
9
6
|
export type DbDriver = ObjectValues<typeof DbDriverEnum>;
|
|
10
|
-
export type PrismaTransactionOptions = {
|
|
11
|
-
dbDriver?: DbDriver;
|
|
12
|
-
retriesAllowed?: number;
|
|
13
|
-
baseRetryDelayMs?: number;
|
|
14
|
-
maxRetryDelayMs?: number;
|
|
15
|
-
maxTimeout?: number;
|
|
16
|
-
maxWait?: number;
|
|
17
|
-
timeout?: number;
|
|
18
|
-
isolationLevel?: CockroachDbIsolationLevel;
|
|
19
|
-
};
|
|
20
|
-
export type PrismaTransactionBasicOptions = Omit<PrismaTransactionOptions, 'maxWait' | 'timeout' | 'maxTimeout'>;
|
|
21
|
-
export type PrismaTransactionClient<P> = Omit<P, runtime.ITXClientDenyList>;
|
|
22
|
-
export type PrismaTransactionFn<T, P> = (prisma: PrismaTransactionClient<P>) => Promise<T>;
|
|
23
|
-
export type PrismaTransactionReturnType<T> = Either<unknown, T | runtime.Types.Utils.UnwrapTuple<Prisma.PrismaPromise<unknown>[]>>;
|
|
24
|
-
/**
|
|
25
|
-
* If we try to use `Omit<Prisma.PrismaClientOptions['transactionOptions'], 'isolationLevel'>` to override isolationLevel
|
|
26
|
-
* we start to get lint errors about maxWait and timeout not being part of the transactionOptions type.
|
|
27
|
-
*
|
|
28
|
-
* for that reason, and as this is a temporal solution in the meantime Prisma includes ReadCommitted as a valid isolation
|
|
29
|
-
* level for CockroachDB, we are using this type to override the transactionOptions which is basically a copy of
|
|
30
|
-
* Prisma.PrismaClientOptions['transactionOptions']
|
|
31
|
-
*/
|
|
32
|
-
type PrismaClientTransactionOptions = {
|
|
33
|
-
isolationLevel?: CockroachDbIsolationLevel;
|
|
34
|
-
maxWait?: number;
|
|
35
|
-
timeout?: number;
|
|
36
|
-
};
|
|
37
|
-
/**
|
|
38
|
-
* this is a temporal solution in the meantime Prisma includes ReadCommitted as a valid isolation level for CockroachDB
|
|
39
|
-
*/
|
|
40
|
-
export type PrismaClientFactoryOptions = Omit<Prisma.PrismaClientOptions, 'transactionOptions'> & {
|
|
41
|
-
dbDriver?: DbDriver;
|
|
42
|
-
transactionOptions?: PrismaClientTransactionOptions;
|
|
43
|
-
};
|
|
44
7
|
export {};
|
package/dist/types.js
CHANGED
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,YAAY,EAAE,aAAa;IAC3B,QAAQ,EAAE,UAAU;CACZ,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lokalise/prisma-utils",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"files": [
|
|
@@ -23,39 +23,34 @@
|
|
|
23
23
|
"clean": "rimraf dist",
|
|
24
24
|
"lint": "biome check . && tsc",
|
|
25
25
|
"lint:fix": "biome check --write",
|
|
26
|
-
"
|
|
27
|
-
"db:migration:dev": "prisma migrate dev",
|
|
26
|
+
"db:migration:dev": "prisma migrate dev --config=./prisma/prisma.config",
|
|
28
27
|
"db:update-client": "prisma generate",
|
|
29
|
-
"db:wait": "while ! echo \"SELECT 1;\" | prisma db execute --stdin --schema prisma/schema.prisma; do sleep 1; done",
|
|
30
28
|
"test": "vitest run",
|
|
31
|
-
"test:migrate": "cross-env NODE_ENV=test prisma migrate reset --force",
|
|
32
|
-
"pretest:ci": "
|
|
29
|
+
"test:migrate": "cross-env NODE_ENV=test prisma migrate reset --config=./prisma/prisma.config --force",
|
|
30
|
+
"pretest:ci": "docker compose up -d --wait && npm run test:migrate",
|
|
33
31
|
"test:ci": "npm run test",
|
|
34
|
-
"
|
|
32
|
+
"posttest:ci": "docker compose down",
|
|
35
33
|
"prepublishOnly": "npm run build",
|
|
36
34
|
"package-version": "echo $npm_package_version",
|
|
37
35
|
"postversion": "biome check --write package.json"
|
|
38
36
|
},
|
|
39
|
-
"dependencies": {
|
|
40
|
-
"@lokalise/node-core": "^14.4.2"
|
|
41
|
-
},
|
|
42
37
|
"peerDependencies": {
|
|
43
|
-
"@
|
|
44
|
-
"prisma": "
|
|
38
|
+
"@lokalise/node-core": ">=14.7.4",
|
|
39
|
+
"@prisma/client": "^7.0.0",
|
|
40
|
+
"prisma": "^7.0.0",
|
|
41
|
+
"prom-client": ">=15.0.0"
|
|
45
42
|
},
|
|
46
43
|
"devDependencies": {
|
|
47
44
|
"@biomejs/biome": "^2.3.7",
|
|
48
|
-
"@lokalise/backend-http-client": "^9.0.0",
|
|
49
45
|
"@lokalise/biome-config": "^3.1.0",
|
|
50
|
-
"@lokalise/fastify-extras": "30.6.0",
|
|
51
46
|
"@lokalise/tsconfig": "^3.1.0",
|
|
52
|
-
"@prisma/
|
|
47
|
+
"@prisma/adapter-pg": "^7.4.0",
|
|
48
|
+
"@prisma/client": "^7.4.0",
|
|
53
49
|
"@vitest/coverage-v8": "^4.0.15",
|
|
54
50
|
"cross-env": "^10.0.0",
|
|
55
|
-
"prisma": "
|
|
51
|
+
"prisma": "^7.4.0",
|
|
56
52
|
"rimraf": "^6.0.1",
|
|
57
53
|
"typescript": "5.9.3",
|
|
58
|
-
"vitest": "^4.0.15"
|
|
59
|
-
"zod": "^4.3.6"
|
|
54
|
+
"vitest": "^4.0.15"
|
|
60
55
|
}
|
|
61
56
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"isolationLevel.js","sourceRoot":"","sources":["../../src/isolation_level/isolationLevel.ts"],"names":[],"mappings":""}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export type CollectionScheduler = {
|
|
2
|
-
start: () => void;
|
|
3
|
-
stop: () => void;
|
|
4
|
-
};
|
|
5
|
-
export declare class PromiseBasedCollectionScheduler implements CollectionScheduler {
|
|
6
|
-
private active;
|
|
7
|
-
private readonly collectionIntervalInMs;
|
|
8
|
-
private readonly collect;
|
|
9
|
-
constructor(collectionIntervalInMs: number, collect: () => Promise<void>);
|
|
10
|
-
start(): Promise<void>;
|
|
11
|
-
stop(): void;
|
|
12
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { setTimeout } from 'node:timers/promises';
|
|
2
|
-
export class PromiseBasedCollectionScheduler {
|
|
3
|
-
active = true;
|
|
4
|
-
collectionIntervalInMs;
|
|
5
|
-
collect;
|
|
6
|
-
constructor(collectionIntervalInMs, collect) {
|
|
7
|
-
this.collectionIntervalInMs = collectionIntervalInMs;
|
|
8
|
-
this.collect = collect;
|
|
9
|
-
}
|
|
10
|
-
async start() {
|
|
11
|
-
while (this.active) {
|
|
12
|
-
await setTimeout(this.collectionIntervalInMs);
|
|
13
|
-
await this.collect();
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
stop() {
|
|
17
|
-
this.active = false;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
//# sourceMappingURL=CollectionScheduler.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"CollectionScheduler.js","sourceRoot":"","sources":["../../src/plugins/CollectionScheduler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAOjD,MAAM,OAAO,+BAA+B;IAClC,MAAM,GAAG,IAAI,CAAA;IACJ,sBAAsB,CAAQ;IAC9B,OAAO,CAAqB;IAE7C,YAAY,sBAA8B,EAAE,OAA4B;QACtE,IAAI,CAAC,sBAAsB,GAAG,sBAAsB,CAAA;QACpD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;IACxB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC;YACnB,MAAM,UAAU,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAA;YAC7C,MAAM,IAAI,CAAC,OAAO,EAAE,CAAA;QACtB,CAAC;IACH,CAAC;IAED,IAAI;QACF,IAAI,CAAC,MAAM,GAAG,KAAK,CAAA;IACrB,CAAC;CACF"}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import type { PrismaClient } from '@prisma/client';
|
|
2
|
-
import type { FastifyBaseLogger } from 'fastify';
|
|
3
|
-
import * as prometheus from 'prom-client';
|
|
4
|
-
export type PrometheusMetricsDefinitions = {
|
|
5
|
-
counters: Record<string, prometheus.Counter<'prisma' | 'connection-pool'>>;
|
|
6
|
-
gauges: Record<string, prometheus.Gauge<'prisma' | 'connection-pool'>>;
|
|
7
|
-
histograms: Record<string, prometheus.Histogram<'prisma' | 'connection-pool'>>;
|
|
8
|
-
keys: string[];
|
|
9
|
-
};
|
|
10
|
-
export type MetricCollectorOptions = {
|
|
11
|
-
metricsPrefix: string;
|
|
12
|
-
};
|
|
13
|
-
export declare class MetricsCollector {
|
|
14
|
-
private readonly prisma;
|
|
15
|
-
private readonly options;
|
|
16
|
-
private readonly registry;
|
|
17
|
-
private readonly logger;
|
|
18
|
-
private metrics;
|
|
19
|
-
constructor(prisma: PrismaClient, options: MetricCollectorOptions, registry: prometheus.Registry, logger: FastifyBaseLogger);
|
|
20
|
-
/**
|
|
21
|
-
* Updates metrics for prisma.
|
|
22
|
-
* If metric was not registered before it will be registered here.
|
|
23
|
-
*/
|
|
24
|
-
collect(prefix: string): Promise<void>;
|
|
25
|
-
private registerNewMetrics;
|
|
26
|
-
/**
|
|
27
|
-
* Stops the metrics collection and cleans up resources
|
|
28
|
-
*/
|
|
29
|
-
dispose(): Promise<void>;
|
|
30
|
-
private registerMetrics;
|
|
31
|
-
/**
|
|
32
|
-
* If metrics are already registered, we just return them to avoid triggering a Prometheus error.
|
|
33
|
-
*/
|
|
34
|
-
private getRegisteredMetrics;
|
|
35
|
-
private getJsonMetrics;
|
|
36
|
-
}
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import * as prometheus from 'prom-client';
|
|
2
|
-
function registerMetrics(_prefix, jsonMetrics) {
|
|
3
|
-
const metrics = {
|
|
4
|
-
counters: {},
|
|
5
|
-
gauges: {},
|
|
6
|
-
histograms: {},
|
|
7
|
-
keys: [],
|
|
8
|
-
};
|
|
9
|
-
for (const metric of jsonMetrics.counters) {
|
|
10
|
-
metrics.counters[metric.key] = new prometheus.Counter({
|
|
11
|
-
name: metric.key,
|
|
12
|
-
help: metric.description,
|
|
13
|
-
labelNames: ['prisma', 'connection_pool'],
|
|
14
|
-
});
|
|
15
|
-
metrics.keys.push(metric.key);
|
|
16
|
-
}
|
|
17
|
-
for (const metric of jsonMetrics.gauges) {
|
|
18
|
-
metrics.gauges[metric.key] = new prometheus.Gauge({
|
|
19
|
-
name: metric.key,
|
|
20
|
-
help: metric.description,
|
|
21
|
-
labelNames: ['prisma', 'connection_pool'],
|
|
22
|
-
});
|
|
23
|
-
metrics.keys.push(metric.key);
|
|
24
|
-
}
|
|
25
|
-
for (const metric of jsonMetrics.histograms) {
|
|
26
|
-
metrics.histograms[metric.key] = new prometheus.Histogram({
|
|
27
|
-
name: metric.key,
|
|
28
|
-
help: metric.description,
|
|
29
|
-
buckets: metric.value.buckets.filter((bucket) => bucket[1] === 0).map((bucket) => bucket[0]),
|
|
30
|
-
labelNames: ['prisma', 'connection_pool'],
|
|
31
|
-
});
|
|
32
|
-
metrics.keys.push(metric.key);
|
|
33
|
-
}
|
|
34
|
-
return metrics;
|
|
35
|
-
}
|
|
36
|
-
function getMetricKeys(_prefix, jsonMetrics) {
|
|
37
|
-
const metricKeys = [];
|
|
38
|
-
metricKeys.push(...jsonMetrics.counters.map((metric) => metric.key));
|
|
39
|
-
metricKeys.push(...jsonMetrics.gauges.map((metric) => metric.key));
|
|
40
|
-
metricKeys.push(...jsonMetrics.histograms.map((metric) => metric.key));
|
|
41
|
-
return metricKeys;
|
|
42
|
-
}
|
|
43
|
-
export class MetricsCollector {
|
|
44
|
-
prisma;
|
|
45
|
-
options;
|
|
46
|
-
registry;
|
|
47
|
-
logger;
|
|
48
|
-
metrics;
|
|
49
|
-
constructor(prisma, options, registry, logger) {
|
|
50
|
-
this.prisma = prisma;
|
|
51
|
-
this.options = options;
|
|
52
|
-
this.registry = registry;
|
|
53
|
-
this.logger = logger;
|
|
54
|
-
this.metrics = {
|
|
55
|
-
counters: {},
|
|
56
|
-
gauges: {},
|
|
57
|
-
histograms: {},
|
|
58
|
-
keys: [],
|
|
59
|
-
};
|
|
60
|
-
this.registerMetrics(this.registry, this.options).then((result) => {
|
|
61
|
-
this.metrics = result;
|
|
62
|
-
this.logger.debug({}, `Prisma metrics registered ${result.keys}`);
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Updates metrics for prisma.
|
|
67
|
-
* If metric was not registered before it will be registered here.
|
|
68
|
-
*/
|
|
69
|
-
async collect(prefix) {
|
|
70
|
-
try {
|
|
71
|
-
const nonRegisteredMetrics = {
|
|
72
|
-
counters: [],
|
|
73
|
-
gauges: [],
|
|
74
|
-
histograms: [],
|
|
75
|
-
};
|
|
76
|
-
const jsonMetrics = await this.getJsonMetrics();
|
|
77
|
-
for (const counterMetric of jsonMetrics.counters) {
|
|
78
|
-
const existingMetric = this.metrics.counters[counterMetric.key];
|
|
79
|
-
/* c8 ignore start */
|
|
80
|
-
if (!existingMetric) {
|
|
81
|
-
nonRegisteredMetrics.counters.push(counterMetric);
|
|
82
|
-
continue;
|
|
83
|
-
}
|
|
84
|
-
/* c8 ignore stop */
|
|
85
|
-
// we need to reset counter since prisma returns already the accumulated counter value
|
|
86
|
-
existingMetric.reset();
|
|
87
|
-
existingMetric.inc(counterMetric.value);
|
|
88
|
-
}
|
|
89
|
-
for (const gaugeMetric of jsonMetrics.gauges) {
|
|
90
|
-
const existingMetric = this.metrics.gauges[gaugeMetric.key];
|
|
91
|
-
/* c8 ignore start */
|
|
92
|
-
if (!existingMetric) {
|
|
93
|
-
nonRegisteredMetrics.gauges.push(gaugeMetric);
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
/* c8 ignore stop */
|
|
97
|
-
existingMetric.set(gaugeMetric.value);
|
|
98
|
-
}
|
|
99
|
-
for (const histogramMetric of jsonMetrics.histograms) {
|
|
100
|
-
const existingMetric = this.metrics.histograms[histogramMetric.key];
|
|
101
|
-
/* c8 ignore start */
|
|
102
|
-
if (!existingMetric) {
|
|
103
|
-
nonRegisteredMetrics.histograms.push(histogramMetric);
|
|
104
|
-
continue;
|
|
105
|
-
}
|
|
106
|
-
/* c8 ignore stop */
|
|
107
|
-
existingMetric.observe(histogramMetric.value.count);
|
|
108
|
-
}
|
|
109
|
-
this.registerNewMetrics(prefix, nonRegisteredMetrics);
|
|
110
|
-
}
|
|
111
|
-
catch (err) {
|
|
112
|
-
/* c8 ignore start */
|
|
113
|
-
this.logger.error(err);
|
|
114
|
-
}
|
|
115
|
-
/* c8 ignore stop */
|
|
116
|
-
}
|
|
117
|
-
registerNewMetrics(prefix, nonRegisteredMetrics) {
|
|
118
|
-
if (!nonRegisteredMetrics.counters.length &&
|
|
119
|
-
!nonRegisteredMetrics.gauges.length &&
|
|
120
|
-
!nonRegisteredMetrics.histograms.length) {
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
/* c8 ignore start */
|
|
124
|
-
const newMetrics = registerMetrics(prefix, nonRegisteredMetrics);
|
|
125
|
-
for (const [key, value] of Object.entries(newMetrics.counters)) {
|
|
126
|
-
this.metrics.counters[key] = value;
|
|
127
|
-
}
|
|
128
|
-
for (const [key, value] of Object.entries(newMetrics.gauges)) {
|
|
129
|
-
this.metrics.gauges[key] = value;
|
|
130
|
-
}
|
|
131
|
-
for (const [key, value] of Object.entries(newMetrics.histograms)) {
|
|
132
|
-
this.metrics.histograms[key] = value;
|
|
133
|
-
}
|
|
134
|
-
this.logger.debug({}, `Prisma metrics registered ${newMetrics.keys}`);
|
|
135
|
-
/* c8 ignore stop */
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Stops the metrics collection and cleans up resources
|
|
139
|
-
*/
|
|
140
|
-
async dispose() { }
|
|
141
|
-
async registerMetrics(registry, { metricsPrefix }) {
|
|
142
|
-
const jsonMetrics = await this.getJsonMetrics();
|
|
143
|
-
const metricNames = getMetricKeys(metricsPrefix, jsonMetrics);
|
|
144
|
-
const existingMetrics = this.getRegisteredMetrics(registry, metricNames);
|
|
145
|
-
if (existingMetrics) {
|
|
146
|
-
/* c8 ignore start */
|
|
147
|
-
return existingMetrics;
|
|
148
|
-
}
|
|
149
|
-
/* c8 ignore stop */
|
|
150
|
-
return registerMetrics(metricsPrefix, jsonMetrics);
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* If metrics are already registered, we just return them to avoid triggering a Prometheus error.
|
|
154
|
-
*/
|
|
155
|
-
getRegisteredMetrics(registry, metricNames) {
|
|
156
|
-
if (!metricNames.length)
|
|
157
|
-
return;
|
|
158
|
-
/* c8 ignore start */
|
|
159
|
-
const retrievedMetrics = registry.getMetricsAsArray();
|
|
160
|
-
if (!retrievedMetrics.length)
|
|
161
|
-
return;
|
|
162
|
-
const returnValue = {
|
|
163
|
-
counters: {},
|
|
164
|
-
histograms: {},
|
|
165
|
-
gauges: {},
|
|
166
|
-
};
|
|
167
|
-
for (const metric of retrievedMetrics) {
|
|
168
|
-
if (!metricNames.includes(metric.name)) {
|
|
169
|
-
continue;
|
|
170
|
-
}
|
|
171
|
-
if (metric.type.toString() === 'counter') {
|
|
172
|
-
returnValue.counters[metric.name] = metric;
|
|
173
|
-
}
|
|
174
|
-
if (metric.type.toString() === 'gauge') {
|
|
175
|
-
returnValue.gauges[metric.name] = metric;
|
|
176
|
-
}
|
|
177
|
-
if (metric.type.toString() === 'histogram') {
|
|
178
|
-
returnValue.histograms[metric.name] = metric;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
return returnValue;
|
|
182
|
-
/* c8 ignore stop */
|
|
183
|
-
}
|
|
184
|
-
getJsonMetrics() {
|
|
185
|
-
return this.prisma.$metrics.json();
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
//# sourceMappingURL=MetricsCollector.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"MetricsCollector.js","sourceRoot":"","sources":["../../src/plugins/MetricsCollector.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { FastifyPluginCallback } from 'fastify';
|
|
2
|
-
import 'fastify-metrics';
|
|
3
|
-
import type { PrismaClient } from '@prisma/client';
|
|
4
|
-
import type { MetricCollectorOptions } from './MetricsCollector.ts';
|
|
5
|
-
declare module 'fastify' {
|
|
6
|
-
interface FastifyInstance {
|
|
7
|
-
prismaMetrics: {
|
|
8
|
-
collect: () => Promise<void>;
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
export type PrismaMetricsPluginOptions = {
|
|
13
|
-
prisma: PrismaClient;
|
|
14
|
-
collectionOptions?: {
|
|
15
|
-
type: 'interval';
|
|
16
|
-
intervalInMs: number;
|
|
17
|
-
} | {
|
|
18
|
-
type: 'manual';
|
|
19
|
-
};
|
|
20
|
-
} & Partial<MetricCollectorOptions>;
|
|
21
|
-
export declare const prismaMetricsPlugin: FastifyPluginCallback<PrismaMetricsPluginOptions>;
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import 'fastify-metrics';
|
|
2
|
-
import fp from 'fastify-plugin';
|
|
3
|
-
import { PromiseBasedCollectionScheduler } from "./CollectionScheduler.js";
|
|
4
|
-
import { MetricsCollector } from "./MetricsCollector.js";
|
|
5
|
-
function plugin(fastify, pluginOptions, next) {
|
|
6
|
-
if (!fastify.metrics) {
|
|
7
|
-
return next(new Error('No Prometheus Client found, Prisma metrics plugin requires `fastify-metrics` plugin to be registered'));
|
|
8
|
-
}
|
|
9
|
-
const options = {
|
|
10
|
-
collectionOptions: {
|
|
11
|
-
type: 'interval',
|
|
12
|
-
intervalInMs: 5000,
|
|
13
|
-
},
|
|
14
|
-
...pluginOptions,
|
|
15
|
-
metricsPrefix: 'prisma',
|
|
16
|
-
};
|
|
17
|
-
try {
|
|
18
|
-
const collector = new MetricsCollector(options.prisma, options, fastify.metrics.client.register, fastify.log);
|
|
19
|
-
const collectFn = async () => await collector.collect(options.metricsPrefix);
|
|
20
|
-
let scheduler;
|
|
21
|
-
if (options.collectionOptions.type === 'interval') {
|
|
22
|
-
scheduler = new PromiseBasedCollectionScheduler(options.collectionOptions.intervalInMs, collectFn);
|
|
23
|
-
// Void is set so the scheduler can run indefinitely
|
|
24
|
-
void scheduler.start();
|
|
25
|
-
}
|
|
26
|
-
fastify.addHook('onClose', async () => {
|
|
27
|
-
if (scheduler) {
|
|
28
|
-
scheduler.stop();
|
|
29
|
-
}
|
|
30
|
-
await collector.dispose();
|
|
31
|
-
});
|
|
32
|
-
fastify.decorate('prismaMetrics', {
|
|
33
|
-
collect: collectFn,
|
|
34
|
-
});
|
|
35
|
-
next();
|
|
36
|
-
/* c8 ignore start */
|
|
37
|
-
}
|
|
38
|
-
catch (err) {
|
|
39
|
-
return next(err instanceof Error
|
|
40
|
-
? err
|
|
41
|
-
: new Error('Unknown error in prisma-metrics-plugin', { cause: err }));
|
|
42
|
-
}
|
|
43
|
-
/* c8 ignore stop */
|
|
44
|
-
}
|
|
45
|
-
export const prismaMetricsPlugin = fp(plugin, {
|
|
46
|
-
fastify: '5.x',
|
|
47
|
-
name: 'prisma-metrics-plugin',
|
|
48
|
-
});
|
|
49
|
-
//# sourceMappingURL=prismaMetricsPlugin.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prismaMetricsPlugin.js","sourceRoot":"","sources":["../../src/plugins/prismaMetricsPlugin.ts"],"names":[],"mappings":"AACA,OAAO,iBAAiB,CAAA;AAExB,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAE/B,OAAO,EAAE,+BAA+B,EAAE,MAAM,0BAA0B,CAAA;AAE1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAuBxD,SAAS,MAAM,CACb,OAAwB,EACxB,aAAyC,EACzC,IAA2B;IAE3B,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACrB,OAAO,IAAI,CACT,IAAI,KAAK,CACP,sGAAsG,CACvG,CACF,CAAA;IACH,CAAC;IAED,MAAM,OAAO,GAAG;QACd,iBAAiB,EAAE;YACjB,IAAI,EAAE,UAAU;YAChB,YAAY,EAAE,IAAI;SACnB;QACD,GAAG,aAAa;QAChB,aAAa,EAAE,QAAQ;KACa,CAAA;IAEtC,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,gBAAgB,CACpC,OAAO,CAAC,MAAM,EACd,OAAO,EACP,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,EAC/B,OAAO,CAAC,GAAG,CACZ,CAAA;QACD,MAAM,SAAS,GAAG,KAAK,IAAI,EAAE,CAAC,MAAM,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAA;QAC5E,IAAI,SAA8B,CAAA;QAElC,IAAI,OAAO,CAAC,iBAAiB,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAClD,SAAS,GAAG,IAAI,+BAA+B,CAC7C,OAAO,CAAC,iBAAiB,CAAC,YAAY,EACtC,SAAS,CACV,CAAA;YAED,oDAAoD;YACpD,KAAK,SAAS,CAAC,KAAK,EAAE,CAAA;QACxB,CAAC;QAED,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;YACpC,IAAI,SAAS,EAAE,CAAC;gBACd,SAAS,CAAC,IAAI,EAAE,CAAA;YAClB,CAAC;YACD,MAAM,SAAS,CAAC,OAAO,EAAE,CAAA;QAC3B,CAAC,CAAC,CAAA;QAEF,OAAO,CAAC,QAAQ,CAAC,eAAe,EAAE;YAChC,OAAO,EAAE,SAAS;SACnB,CAAC,CAAA;QAEF,IAAI,EAAE,CAAA;QACN,qBAAqB;IACvB,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,OAAO,IAAI,CACT,GAAG,YAAY,KAAK;YAClB,CAAC,CAAC,GAAG;YACL,CAAC,CAAC,IAAI,KAAK,CAAC,wCAAwC,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CACxE,CAAA;IACH,CAAC;IACD,oBAAoB;AACtB,CAAC;AAED,MAAM,CAAC,MAAM,mBAAmB,GAC9B,EAAE,CAA6B,MAAM,EAAE;IACrC,OAAO,EAAE,KAAK;IACd,IAAI,EAAE,uBAAuB;CAC9B,CAAC,CAAA"}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { Prisma, PrismaClient } from '@prisma/client';
|
|
2
|
-
import type { PrismaClientFactoryOptions } from './types.ts';
|
|
3
|
-
type PrismaClientConstructor<P extends PrismaClient> = new (options: Prisma.PrismaClientOptions) => P;
|
|
4
|
-
export declare const prismaClientFactory: <P extends PrismaClient>(PrismaClient: PrismaClientConstructor<P>, options?: PrismaClientFactoryOptions) => P;
|
|
5
|
-
export {};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
const defaultOptions = {
|
|
2
|
-
transactionOptions: { isolationLevel: 'ReadCommitted' },
|
|
3
|
-
};
|
|
4
|
-
export const prismaClientFactory = (PrismaClient, options = {}) => {
|
|
5
|
-
options.transactionOptions = {
|
|
6
|
-
...defaultOptions.transactionOptions,
|
|
7
|
-
...options.transactionOptions,
|
|
8
|
-
};
|
|
9
|
-
return new PrismaClient(options);
|
|
10
|
-
};
|
|
11
|
-
//# sourceMappingURL=prismaClientFactory.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prismaClientFactory.js","sourceRoot":"","sources":["../src/prismaClientFactory.ts"],"names":[],"mappings":"AAGA,MAAM,cAAc,GAA+B;IACjD,kBAAkB,EAAE,EAAE,cAAc,EAAE,eAAe,EAAE;CACxD,CAAA;AAMD,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,YAAwC,EACxC,UAAsC,EAAE,EACrC,EAAE;IACL,OAAO,CAAC,kBAAkB,GAAG;QAC3B,GAAG,cAAc,CAAC,kBAAkB;QACpC,GAAG,OAAO,CAAC,kBAAkB;KAC9B,CAAA;IAED,OAAO,IAAI,YAAY,CAAC,OAAO,CAAC,CAAA;AAClC,CAAC,CAAA"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { Either } from '@lokalise/node-core';
|
|
2
|
-
import type { Prisma, PrismaClient } from '@prisma/client';
|
|
3
|
-
import type * as runtime from '@prisma/client/runtime/library';
|
|
4
|
-
import type { PrismaTransactionBasicOptions, PrismaTransactionFn, PrismaTransactionOptions } from './types.ts';
|
|
5
|
-
/**
|
|
6
|
-
* Perform a Prisma DB transaction with automatic retries if needed.
|
|
7
|
-
*
|
|
8
|
-
* @template T | T extends Prisma.PrismaPromise<unknown>[]
|
|
9
|
-
* @param {PrismaClient} prisma
|
|
10
|
-
* @param {PrismaTransactionFn<T> | Prisma.PrismaPromise<unknown>[]} arg operation to perform into the transaction
|
|
11
|
-
* @param {PrismaTransactionOptions | PrismaTransactionBasicOptions} options transaction configuration
|
|
12
|
-
* @return {Promise<PrismaTransactionReturnType<T>>}
|
|
13
|
-
*/
|
|
14
|
-
export declare const prismaTransaction: {
|
|
15
|
-
<T, P extends PrismaClient>(prisma: P, fn: PrismaTransactionFn<T, P>, options?: PrismaTransactionOptions): Promise<Either<unknown, T>>;
|
|
16
|
-
<T extends Prisma.PrismaPromise<unknown>[], P extends PrismaClient>(prisma: P, args: [...T], options?: PrismaTransactionBasicOptions): Promise<Either<unknown, runtime.Types.Utils.UnwrapTuple<T>>>;
|
|
17
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prismaTransaction.js","sourceRoot":"","sources":["../src/prismaTransaction.ts"],"names":[],"mappings":"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"}
|