@fluojs/prisma 1.0.0-beta.5 → 1.0.0-beta.6
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.ko.md +13 -0
- package/README.md +13 -0
- package/dist/service.d.ts +4 -0
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +72 -4
- package/dist/status.js +2 -2
- package/package.json +4 -4
package/README.ko.md
CHANGED
|
@@ -14,6 +14,7 @@ fluo 애플리케이션을 위한 Prisma 라이프사이클 및 ALS 기반 트
|
|
|
14
14
|
- [여러 클라이언트를 위한 이름 있는 등록](#여러-클라이언트를-위한-이름-있는-등록)
|
|
15
15
|
- [수동 트랜잭션](#수동-트랜잭션)
|
|
16
16
|
- [자동 요청 트랜잭션](#자동-요청-트랜잭션)
|
|
17
|
+
- [종료와 status 계약](#종료와-status-계약)
|
|
17
18
|
- [비동기 설정과 격리](#비동기-설정과-격리)
|
|
18
19
|
- [수동 모듈 조합](#수동-모듈-조합)
|
|
19
20
|
- [공개 API 개요](#공개-api-개요)
|
|
@@ -135,6 +136,18 @@ class UserController {
|
|
|
135
136
|
|
|
136
137
|
`PrismaTransactionInterceptor`는 기본 이름 없는 `PrismaService`를 대상으로 합니다. 이름 있는 다중 클라이언트 등록에서는 해당 이름의 `PrismaService`를 주입한 뒤 필요한 위치에서 명시적으로 `transaction()` / `requestTransaction()` 경계를 여세요.
|
|
137
138
|
|
|
139
|
+
### 종료와 status 계약
|
|
140
|
+
|
|
141
|
+
`PrismaService.requestTransaction(...)`은 정상 serving 전과 중에는 사용할 수 있지만, 애플리케이션 종료가 시작된 뒤에는 새 요청 범위 트랜잭션을 거부합니다. 종료 중에는 열린 요청 트랜잭션을 abort하고, 바깥 트랜잭션 경계가 settle될 때까지 추적한 뒤, 모두 drain한 다음 `$disconnect()`를 실행합니다. 기존 수동 `transaction(...)` 경계 안에서 열린 중첩 `requestTransaction(...)` 호출도 여기에 포함됩니다. 이 호출은 ambient Prisma transaction client를 재사용하고, 바깥 경계가 끝날 때까지 `details.activeRequestTransactions`에 남으며, 두 번째 Prisma 트랜잭션을 열지 않습니다.
|
|
142
|
+
|
|
143
|
+
`createPrismaPlatformStatusSnapshot(...)`와 `PrismaService.createPlatformStatusSnapshot()`은 같은 라이프사이클 계약을 진단 surface에 노출합니다.
|
|
144
|
+
|
|
145
|
+
- `readiness.status`는 Prisma가 종료 중이거나 stopped 상태일 때, 그리고 `strictTransactions`가 켜져 있는데 `$transaction(...)`을 지원하지 않을 때 `not-ready`입니다.
|
|
146
|
+
- `health.status`는 종료 중 요청 트랜잭션을 drain하는 동안 `degraded`, disconnect 이후 `unhealthy`입니다.
|
|
147
|
+
- `details.activeRequestTransactions`, `details.lifecycleState`, `details.strictTransactions`, `details.supportsTransaction`, `details.transactionAbortSignalSupport`는 현재 요청 트랜잭션과 트랜잭션 capability 상태를 설명합니다.
|
|
148
|
+
- `details.transactionContext: 'als'`는 요청 및 서비스 트랜잭션 경계가 사용하는 async-local transaction context를 식별합니다.
|
|
149
|
+
- `ownership.externallyManaged: false`와 `ownership.ownsResources: true`는 패키지가 fluo 애플리케이션 라이프사이클 안에서 등록된 클라이언트의 `$connect()` / `$disconnect()` lifecycle hook을 소유한다는 의미입니다.
|
|
150
|
+
|
|
138
151
|
### 비동기 설정과 격리
|
|
139
152
|
|
|
140
153
|
주입된 설정이나 다른 비동기 소스에서 Prisma 클라이언트를 만들어야 할 때는 `PrismaModule.forRootAsync(...)`를 사용하세요. 비동기 factory는 애플리케이션 컨테이너마다 한 번 resolve되며, 테스트나 여러 앱을 띄우는 프로세스에서 같은 모듈 정의를 재사용하더라도 별도 bootstrap 사이에서 공유되지 않습니다.
|
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@ Prisma lifecycle and ALS-backed transaction context for fluo applications. Conne
|
|
|
14
14
|
- [Named Registrations for Multiple Clients](#named-registrations-for-multiple-clients)
|
|
15
15
|
- [Manual Transactions](#manual-transactions)
|
|
16
16
|
- [Automatic Request Transactions](#automatic-request-transactions)
|
|
17
|
+
- [Shutdown and Status Contracts](#shutdown-and-status-contracts)
|
|
17
18
|
- [Async Configuration and Isolation](#async-configuration-and-isolation)
|
|
18
19
|
- [Manual Module Composition](#manual-module-composition)
|
|
19
20
|
- [Public API Overview](#public-api-overview)
|
|
@@ -135,6 +136,18 @@ class UserController {
|
|
|
135
136
|
|
|
136
137
|
`PrismaTransactionInterceptor` targets the default unnamed `PrismaService`. For named multi-client registrations, inject the corresponding named `PrismaService` and open explicit `transaction()` / `requestTransaction()` boundaries where needed.
|
|
137
138
|
|
|
139
|
+
### Shutdown and Status Contracts
|
|
140
|
+
|
|
141
|
+
`PrismaService.requestTransaction(...)` is available before and during normal serving, but new request-scoped transactions are rejected once application shutdown has started. During shutdown, open request transactions are aborted, tracked until their outer transaction boundary has settled, and drained before `$disconnect()` runs. This includes nested `requestTransaction(...)` calls opened inside an existing manual `transaction(...)` boundary: they reuse the ambient Prisma transaction client, stay visible in `details.activeRequestTransactions` until the outer boundary finishes, and do not open a second Prisma transaction.
|
|
142
|
+
|
|
143
|
+
`createPrismaPlatformStatusSnapshot(...)` and `PrismaService.createPlatformStatusSnapshot()` expose the same lifecycle contract to diagnostics surfaces:
|
|
144
|
+
|
|
145
|
+
- `readiness.status` is `not-ready` while Prisma is shutting down or stopped, and when `strictTransactions` is enabled without `$transaction(...)` support.
|
|
146
|
+
- `health.status` is `degraded` while request transactions are draining during shutdown and `unhealthy` after disconnect.
|
|
147
|
+
- `details.activeRequestTransactions`, `details.lifecycleState`, `details.strictTransactions`, `details.supportsTransaction`, and `details.transactionAbortSignalSupport` describe the current request transaction and transaction-capability state.
|
|
148
|
+
- `details.transactionContext: 'als'` identifies the async-local transaction context used by request and service transaction boundaries.
|
|
149
|
+
- `ownership.externallyManaged: false` and `ownership.ownsResources: true` mean the package owns the registered client's `$connect()` / `$disconnect()` lifecycle hooks inside the fluo application lifecycle.
|
|
150
|
+
|
|
138
151
|
### Async Configuration and Isolation
|
|
139
152
|
|
|
140
153
|
Use `PrismaModule.forRootAsync(...)` when the Prisma client must be created from injected configuration or another async source. The async factory is resolved once per application container and is not shared across separate bootstraps, even when the same module definition is reused in tests or multi-app processes.
|
package/dist/service.d.ts
CHANGED
|
@@ -77,6 +77,10 @@ export declare class PrismaService<TClient extends PrismaClientLike<TTransaction
|
|
|
77
77
|
* error type/message depends on the runtime abort implementation.
|
|
78
78
|
*/
|
|
79
79
|
requestTransaction<T>(fn: () => Promise<T>, signal?: AbortSignal, options?: TTransactionOptions): Promise<T>;
|
|
80
|
+
private runWithRequestTransactionClient;
|
|
81
|
+
private runNestedRequestTransaction;
|
|
82
|
+
private assertRequestTransactionsAvailable;
|
|
83
|
+
private throwIfRequestAborted;
|
|
80
84
|
private runRequestTransactionWithAbortSignal;
|
|
81
85
|
private canAttemptTransactionAbortSignalOption;
|
|
82
86
|
private runTransactionWithAbortSignalFallback;
|
package/dist/service.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAK3E,OAAO,KAAK,EACV,4BAA4B,EAC5B,6BAA6B,EAC7B,gBAAgB,EAChB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAMpB,UAAU,oBAAoB;IAC5B,kBAAkB,EAAE,OAAO,CAAC;CAC7B;AAoBD;;;;;;GAMG;AACH,qBACa,aAAa,CACxB,OAAO,SAAS,gBAAgB,CAAC,kBAAkB,EAAE,mBAAmB,CAAC,EACzE,kBAAkB,GAAG,4BAA4B,CAAC,OAAO,CAAC,EAC1D,mBAAmB,GAAG,6BAA6B,CAAC,OAAO,CAAC,CAE5D,YAAW,oBAAoB,CAAC,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,CAAC,EAAE,YAAY,EAAE,qBAAqB;IAQpH,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,cAAc;IAPjC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAmE;IAChG,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAuC;IACjF,OAAO,CAAC,6BAA6B,CAA4C;IACjF,OAAO,CAAC,cAAc,CAAgE;gBAGnE,MAAM,EAAE,OAAO,EACf,cAAc,GAAE,oBAAoD;IAGvF;;;;;;;;;OASG;IACH,OAAO,IAAI,OAAO,GAAG,kBAAkB;YAIzB,wBAAwB;IAuChC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ7B,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB5C;;;;OAIG;IACH,4BAA4B;IAY5B;;;;;;;;;;;;;;;;;OAiBG;IACG,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,CAAC,CAAC;IAQrF;;;;;;;;;;;;;;;;;;OAkBG;IACG,kBAAkB,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,CAAC,CAAC;YAkCpG,+BAA+B;YAuB/B,2BAA2B;IAqCzC,OAAO,CAAC,kCAAkC;IAM1C,OAAO,CAAC,qBAAqB;IAM7B,OAAO,CAAC,oCAAoC;IAY5C,OAAO,CAAC,sCAAsC;YAYhC,qCAAqC;IAyBnD,OAAO,CAAC,6BAA6B;IAUrC,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,0BAA0B;IAWlC,OAAO,CAAC,6BAA6B;IAIrC,OAAO,CAAC,+BAA+B;CAGxC"}
|
package/dist/service.js
CHANGED
|
@@ -5,11 +5,12 @@ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e =
|
|
|
5
5
|
function _setFunctionName(e, t, n) { "symbol" == typeof t && (t = (t = t.description) ? "[" + t + "]" : ""); try { Object.defineProperty(e, "name", { configurable: !0, value: n ? n + " " + t : t }); } catch (e) {} return e; }
|
|
6
6
|
function _checkInRHS(e) { if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? typeof e : "null")); return e; }
|
|
7
7
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
8
|
-
import { createRequestAbortContext, raceWithAbort, trackActiveRequestTransaction, untrackActiveRequestTransaction } from '@fluojs/runtime';
|
|
8
|
+
import { createAbortError, createRequestAbortContext, raceWithAbort, trackActiveRequestTransaction, untrackActiveRequestTransaction } from '@fluojs/runtime';
|
|
9
9
|
import { Inject } from '@fluojs/core';
|
|
10
10
|
import { createPrismaPlatformStatusSnapshot } from './status.js';
|
|
11
11
|
import { PRISMA_CLIENT, PRISMA_OPTIONS } from './tokens.js';
|
|
12
12
|
const NESTED_TRANSACTION_OPTIONS_NOT_SUPPORTED_ERROR = 'Nested Prisma transaction options are not supported because the active transaction context is reused.';
|
|
13
|
+
const REQUEST_TRANSACTION_UNAVAILABLE_ERROR = 'Prisma request transactions are not available during shutdown.';
|
|
13
14
|
let _PrismaService;
|
|
14
15
|
/**
|
|
15
16
|
* Prisma runtime facade that owns lifecycle hooks and transaction context access.
|
|
@@ -44,7 +45,7 @@ class PrismaService {
|
|
|
44
45
|
* @returns The request/transaction-scoped client when a transaction is active; otherwise the root client.
|
|
45
46
|
*/
|
|
46
47
|
current() {
|
|
47
|
-
return this.transactions.getStore() ?? this.client;
|
|
48
|
+
return this.transactions.getStore()?.client ?? this.client;
|
|
48
49
|
}
|
|
49
50
|
async runWithTransactionClient(fn, run, options) {
|
|
50
51
|
if (this.transactions.getStore()) {
|
|
@@ -59,7 +60,17 @@ class PrismaService {
|
|
|
59
60
|
}
|
|
60
61
|
return fn();
|
|
61
62
|
}
|
|
62
|
-
|
|
63
|
+
const deferredRequestTransactionHandles = new Set();
|
|
64
|
+
try {
|
|
65
|
+
return await run(transactionClient => this.transactions.run({
|
|
66
|
+
client: transactionClient,
|
|
67
|
+
deferredRequestTransactionHandles
|
|
68
|
+
}, fn), options);
|
|
69
|
+
} finally {
|
|
70
|
+
for (const handle of deferredRequestTransactionHandles) {
|
|
71
|
+
this.untrackActiveRequestTransaction(handle);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
63
74
|
}
|
|
64
75
|
async onModuleInit() {
|
|
65
76
|
if (typeof this.client.$connect === 'function') {
|
|
@@ -138,15 +149,72 @@ class PrismaService {
|
|
|
138
149
|
* error type/message depends on the runtime abort implementation.
|
|
139
150
|
*/
|
|
140
151
|
async requestTransaction(fn, signal, options) {
|
|
152
|
+
const current = this.transactions.getStore();
|
|
153
|
+
if (current) {
|
|
154
|
+
if (options !== undefined) {
|
|
155
|
+
throw new Error(NESTED_TRANSACTION_OPTIONS_NOT_SUPPORTED_ERROR);
|
|
156
|
+
}
|
|
157
|
+
return this.runNestedRequestTransaction(current, fn, signal);
|
|
158
|
+
}
|
|
159
|
+
this.assertRequestTransactionsAvailable();
|
|
141
160
|
const abortContext = createRequestAbortContext(signal);
|
|
142
161
|
const active = this.trackActiveRequestTransaction(abortContext.controller);
|
|
143
162
|
try {
|
|
144
|
-
|
|
163
|
+
const result = await this.runWithRequestTransactionClient(() => raceWithAbort(fn, abortContext.signal), (callback, transactionOptions) => this.runRequestTransactionWithAbortSignal(callback, abortContext.signal, transactionOptions), options, abortContext.signal);
|
|
164
|
+
this.throwIfRequestAborted(abortContext.signal);
|
|
165
|
+
return result;
|
|
145
166
|
} finally {
|
|
146
167
|
abortContext.cleanup();
|
|
147
168
|
this.untrackActiveRequestTransaction(active);
|
|
148
169
|
}
|
|
149
170
|
}
|
|
171
|
+
async runWithRequestTransactionClient(fn, run, options, signal) {
|
|
172
|
+
if (typeof this.client.$transaction !== 'function') {
|
|
173
|
+
if (this.serviceOptions.strictTransactions) {
|
|
174
|
+
throw new Error('Transaction not supported: Prisma client does not implement $transaction.');
|
|
175
|
+
}
|
|
176
|
+
return fn();
|
|
177
|
+
}
|
|
178
|
+
return run(transactionClient => this.transactions.run({
|
|
179
|
+
client: transactionClient,
|
|
180
|
+
requestAbortSignal: signal
|
|
181
|
+
}, fn), options);
|
|
182
|
+
}
|
|
183
|
+
async runNestedRequestTransaction(current, fn, signal) {
|
|
184
|
+
if (current.requestAbortSignal) {
|
|
185
|
+
if (signal) {
|
|
186
|
+
return raceWithAbort(fn, signal);
|
|
187
|
+
}
|
|
188
|
+
return fn();
|
|
189
|
+
}
|
|
190
|
+
this.assertRequestTransactionsAvailable();
|
|
191
|
+
const abortContext = createRequestAbortContext(signal);
|
|
192
|
+
const active = this.trackActiveRequestTransaction(abortContext.controller);
|
|
193
|
+
current.deferredRequestTransactionHandles?.add(active);
|
|
194
|
+
try {
|
|
195
|
+
const result = await this.transactions.run({
|
|
196
|
+
client: current.client,
|
|
197
|
+
requestAbortSignal: abortContext.signal
|
|
198
|
+
}, () => raceWithAbort(fn, abortContext.signal));
|
|
199
|
+
this.throwIfRequestAborted(abortContext.signal);
|
|
200
|
+
return result;
|
|
201
|
+
} finally {
|
|
202
|
+
abortContext.cleanup();
|
|
203
|
+
if (!current.deferredRequestTransactionHandles) {
|
|
204
|
+
this.untrackActiveRequestTransaction(active);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
assertRequestTransactionsAvailable() {
|
|
209
|
+
if (this.lifecycleState === 'shutting-down' || this.lifecycleState === 'stopped') {
|
|
210
|
+
throw new Error(REQUEST_TRANSACTION_UNAVAILABLE_ERROR);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
throwIfRequestAborted(signal) {
|
|
214
|
+
if (signal.aborted) {
|
|
215
|
+
throw createAbortError(signal.reason);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
150
218
|
runRequestTransactionWithAbortSignal(callback, signal, options) {
|
|
151
219
|
if (!this.canAttemptTransactionAbortSignalOption(options)) {
|
|
152
220
|
return this.client.$transaction(callback, options);
|
package/dist/status.js
CHANGED
|
@@ -63,8 +63,8 @@ export function createPrismaPlatformStatusSnapshot(input) {
|
|
|
63
63
|
},
|
|
64
64
|
health: createHealth(input),
|
|
65
65
|
ownership: {
|
|
66
|
-
externallyManaged:
|
|
67
|
-
ownsResources:
|
|
66
|
+
externallyManaged: false,
|
|
67
|
+
ownsResources: true
|
|
68
68
|
},
|
|
69
69
|
readiness: createReadiness(input)
|
|
70
70
|
};
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"transaction",
|
|
10
10
|
"als"
|
|
11
11
|
],
|
|
12
|
-
"version": "1.0.0-beta.
|
|
12
|
+
"version": "1.0.0-beta.6",
|
|
13
13
|
"private": false,
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"repository": {
|
|
@@ -36,10 +36,10 @@
|
|
|
36
36
|
"dist"
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@fluojs/core": "^1.0.0-beta.
|
|
39
|
+
"@fluojs/core": "^1.0.0-beta.6",
|
|
40
40
|
"@fluojs/validation": "^1.0.0-beta.4",
|
|
41
|
-
"@fluojs/http": "^1.0.0-beta.
|
|
42
|
-
"@fluojs/di": "^1.0.0-beta.
|
|
41
|
+
"@fluojs/http": "^1.0.0-beta.11",
|
|
42
|
+
"@fluojs/di": "^1.0.0-beta.8",
|
|
43
43
|
"@fluojs/runtime": "^1.0.0-beta.12"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|