@kronos-ts/postgres 0.6.0 → 0.7.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 +13 -0
- package/dist/adapters/bun-sql.d.ts +2 -1
- package/dist/adapters/bun-sql.d.ts.map +1 -1
- package/dist/adapters/bun-sql.js +5 -0
- package/dist/adapters/bun-sql.js.map +1 -1
- package/dist/adapters/pg.d.ts +2 -1
- package/dist/adapters/pg.d.ts.map +1 -1
- package/dist/adapters/pg.js +5 -0
- package/dist/adapters/pg.js.map +1 -1
- package/dist/adapters/postgres.d.ts +2 -1
- package/dist/adapters/postgres.d.ts.map +1 -1
- package/dist/adapters/postgres.js +5 -0
- package/dist/adapters/postgres.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/postgres-transaction-manager.d.ts +1 -20
- package/dist/postgres-transaction-manager.d.ts.map +1 -1
- package/dist/postgres-transaction-manager.js +4 -26
- package/dist/postgres-transaction-manager.js.map +1 -1
- package/dist/postgres.d.ts +0 -8
- package/dist/postgres.d.ts.map +1 -1
- package/dist/postgres.js +5 -1
- package/dist/postgres.js.map +1 -1
- package/dist/session-timeouts.d.ts +47 -0
- package/dist/session-timeouts.d.ts.map +1 -0
- package/dist/session-timeouts.js +44 -0
- package/dist/session-timeouts.js.map +1 -0
- package/package.json +4 -4
- package/src/adapters/bun-sql.ts +10 -1
- package/src/adapters/pg.ts +10 -1
- package/src/adapters/postgres.ts +10 -1
- package/src/index.ts +10 -0
- package/src/postgres-transaction-manager.ts +3 -51
- package/src/postgres.ts +5 -9
- package/src/session-timeouts.ts +77 -0
package/README.md
CHANGED
|
@@ -94,9 +94,22 @@ import { pgAdapter } from "@kronos-ts/postgres/adapters/pg"
|
|
|
94
94
|
const adapter = pgAdapter({
|
|
95
95
|
connectionString: "postgresql://user:pass@host/db",
|
|
96
96
|
poolConfig: { max: 10 }, // optional pg.Pool overrides
|
|
97
|
+
// Per-transaction safety timeouts, armed via SET LOCAL on every transaction
|
|
98
|
+
// this adapter opens. Defaults: 30s idle-in-transaction, statement off.
|
|
99
|
+
idleInTransactionTimeoutMs: 30_000, // 0 disables
|
|
100
|
+
statementTimeoutMs: 0, // opt in per deployment
|
|
97
101
|
})
|
|
98
102
|
```
|
|
99
103
|
|
|
104
|
+
> **Safety timeouts live on the adapter.** Every transaction opened through the
|
|
105
|
+
> adapter (UoW-scoped commits, the event store's own-tx appends, the scheduler
|
|
106
|
+
> worker) is bounded, and each adapter instance is configured independently — so
|
|
107
|
+
> an event-store adapter and an event-processing adapter pointed at two
|
|
108
|
+
> different databases stay fully decoupled. `idleInTransactionTimeoutMs` is the
|
|
109
|
+
> important one: it stops a stalled transaction from pinning a connection (and
|
|
110
|
+
> `pg_snapshot_xmin`, which gates the tailing query) open indefinitely. The same
|
|
111
|
+
> two options are available on `postgresAdapter` and `bunSqlAdapter`.
|
|
112
|
+
|
|
100
113
|
### postgresAdapter
|
|
101
114
|
|
|
102
115
|
```typescript
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
* a clear runtime error from the connect() call.
|
|
17
17
|
*/
|
|
18
18
|
import type { PostgresAdapter } from "../adapter.js";
|
|
19
|
-
|
|
19
|
+
import { type SessionTimeoutOptions } from "../session-timeouts.js";
|
|
20
|
+
export interface BunSqlAdapterConfig extends SessionTimeoutOptions {
|
|
20
21
|
readonly connectionString: string;
|
|
21
22
|
}
|
|
22
23
|
export declare function bunSqlAdapter(config: BunSqlAdapterConfig): PostgresAdapter;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bun-sql.d.ts","sourceRoot":"","sources":["../../src/adapters/bun-sql.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"bun-sql.d.ts","sourceRoot":"","sources":["../../src/adapters/bun-sql.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,eAAe,CAAA;AAEtB,OAAO,EACL,KAAK,qBAAqB,EAG3B,MAAM,wBAAwB,CAAA;AAE/B,MAAM,WAAW,mBAAoB,SAAQ,qBAAqB;IAChE,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;CAClC;AA6ED,wBAAgB,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,eAAe,CAiI1E"}
|
package/dist/adapters/bun-sql.js
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* a clear runtime error from the connect() call.
|
|
17
17
|
*/
|
|
18
18
|
import { IsolationLevel } from "../adapter.js";
|
|
19
|
+
import { applySessionTimeouts, resolveSessionTimeouts, } from "../session-timeouts.js";
|
|
19
20
|
/**
|
|
20
21
|
* Bun.SQL surfaces SQLSTATE in `err.errno` (not `err.code`). The adapter
|
|
21
22
|
* contract (D-12.12) requires SQLSTATE on `.code` so that `isDcbViolation(err)`
|
|
@@ -71,6 +72,7 @@ function getBunSql() {
|
|
|
71
72
|
export function bunSqlAdapter(config) {
|
|
72
73
|
let sql;
|
|
73
74
|
let disconnected = false;
|
|
75
|
+
const timeouts = resolveSessionTimeouts(config);
|
|
74
76
|
function getInstance() {
|
|
75
77
|
if (!sql) {
|
|
76
78
|
const SQL = getBunSql();
|
|
@@ -135,6 +137,9 @@ export function bunSqlAdapter(config) {
|
|
|
135
137
|
return txSql.unsafe(text, normalizeParams(params)).catch(normalizeBunSqlError);
|
|
136
138
|
},
|
|
137
139
|
};
|
|
140
|
+
// Arm the per-transaction safety timeouts before handing the tx to the
|
|
141
|
+
// caller, so even the very first awaited statement is bounded.
|
|
142
|
+
await applySessionTimeouts(tx, timeouts);
|
|
138
143
|
return fn(tx);
|
|
139
144
|
}).catch(normalizeBunSqlError);
|
|
140
145
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bun-sql.js","sourceRoot":"","sources":["../../src/adapters/bun-sql.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAQH,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"bun-sql.js","sourceRoot":"","sources":["../../src/adapters/bun-sql.ts"],"names":[],"mappings":"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"}
|
package/dist/adapters/pg.d.ts
CHANGED
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { type PoolConfig } from "pg";
|
|
16
16
|
import type { PostgresAdapter } from "../adapter.js";
|
|
17
|
-
|
|
17
|
+
import { type SessionTimeoutOptions } from "../session-timeouts.js";
|
|
18
|
+
export interface PgAdapterConfig extends SessionTimeoutOptions {
|
|
18
19
|
/** Standard libpq URI: postgresql://user:pass@host:port/db */
|
|
19
20
|
readonly connectionString: string;
|
|
20
21
|
/** Optional pg.Pool config overrides (max connections, idleTimeoutMillis, etc.). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pg.d.ts","sourceRoot":"","sources":["../../src/adapters/pg.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAyB,KAAK,UAAU,EAAE,MAAM,IAAI,CAAA;AAC3D,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"pg.d.ts","sourceRoot":"","sources":["../../src/adapters/pg.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAyB,KAAK,UAAU,EAAE,MAAM,IAAI,CAAA;AAC3D,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,eAAe,CAAA;AAEtB,OAAO,EACL,KAAK,qBAAqB,EAG3B,MAAM,wBAAwB,CAAA;AAE/B,MAAM,WAAW,eAAgB,SAAQ,qBAAqB;IAC5D,8DAA8D;IAC9D,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;IACjC,oFAAoF;IACpF,QAAQ,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAA;CAC3D;AAOD,wBAAgB,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,eAAe,CA+JlE"}
|
package/dist/adapters/pg.js
CHANGED
|
@@ -14,11 +14,13 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { Pool } from "pg";
|
|
16
16
|
import { IsolationLevel } from "../adapter.js";
|
|
17
|
+
import { applySessionTimeouts, resolveSessionTimeouts, } from "../session-timeouts.js";
|
|
17
18
|
export function pgAdapter(config) {
|
|
18
19
|
let pool;
|
|
19
20
|
let listenClient;
|
|
20
21
|
const listenSlots = new Map();
|
|
21
22
|
let disconnected = false;
|
|
23
|
+
const timeouts = resolveSessionTimeouts(config);
|
|
22
24
|
function getPool() {
|
|
23
25
|
if (!pool) {
|
|
24
26
|
pool = new Pool({ connectionString: config.connectionString, ...config.poolConfig });
|
|
@@ -100,6 +102,9 @@ export function pgAdapter(config) {
|
|
|
100
102
|
};
|
|
101
103
|
let result;
|
|
102
104
|
try {
|
|
105
|
+
// Arm the per-transaction safety timeouts before handing the tx to
|
|
106
|
+
// the caller, so even the very first awaited statement is bounded.
|
|
107
|
+
await applySessionTimeouts(tx, timeouts);
|
|
103
108
|
result = await fn(tx);
|
|
104
109
|
}
|
|
105
110
|
catch (err) {
|
package/dist/adapters/pg.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pg.js","sourceRoot":"","sources":["../../src/adapters/pg.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,IAAI,EAAoC,MAAM,IAAI,CAAA;AAO3D,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"pg.js","sourceRoot":"","sources":["../../src/adapters/pg.ts"],"names":[],"mappings":"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"}
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
*/
|
|
19
19
|
import postgresClient from "postgres";
|
|
20
20
|
import type { PostgresAdapter } from "../adapter.js";
|
|
21
|
-
|
|
21
|
+
import { type SessionTimeoutOptions } from "../session-timeouts.js";
|
|
22
|
+
export interface PostgresAdapterConfig extends SessionTimeoutOptions {
|
|
22
23
|
readonly connectionString: string;
|
|
23
24
|
/** Additional postgres.js options. `transform.column.from` is forced off regardless. */
|
|
24
25
|
readonly clientOptions?: Parameters<typeof postgresClient>[1];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../src/adapters/postgres.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,cAAc,MAAM,UAAU,CAAA;AAErC,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../src/adapters/postgres.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,cAAc,MAAM,UAAU,CAAA;AAErC,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,eAAe,CAAA;AAEtB,OAAO,EACL,KAAK,qBAAqB,EAG3B,MAAM,wBAAwB,CAAA;AAE/B,MAAM,WAAW,qBAAsB,SAAQ,qBAAqB;IAClE,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;IACjC,wFAAwF;IACxF,QAAQ,CAAC,aAAa,CAAC,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,CAAC,CAAC,CAAA;CAC9D;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,eAAe,CAyG9E"}
|
|
@@ -18,9 +18,11 @@
|
|
|
18
18
|
*/
|
|
19
19
|
import postgresClient from "postgres";
|
|
20
20
|
import { IsolationLevel } from "../adapter.js";
|
|
21
|
+
import { applySessionTimeouts, resolveSessionTimeouts, } from "../session-timeouts.js";
|
|
21
22
|
export function postgresAdapter(config) {
|
|
22
23
|
let sql;
|
|
23
24
|
let disconnected = false;
|
|
25
|
+
const timeouts = resolveSessionTimeouts(config);
|
|
24
26
|
function getSql() {
|
|
25
27
|
if (!sql) {
|
|
26
28
|
sql = postgresClient(config.connectionString, {
|
|
@@ -82,6 +84,9 @@ export function postgresAdapter(config) {
|
|
|
82
84
|
return rows;
|
|
83
85
|
},
|
|
84
86
|
};
|
|
87
|
+
// Arm the per-transaction safety timeouts before handing the tx to the
|
|
88
|
+
// caller, so even the very first awaited statement is bounded.
|
|
89
|
+
await applySessionTimeouts(tx, timeouts);
|
|
85
90
|
return fn(tx);
|
|
86
91
|
}));
|
|
87
92
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres.js","sourceRoot":"","sources":["../../src/adapters/postgres.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,cAAc,MAAM,UAAU,CAAA;AAQrC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"postgres.js","sourceRoot":"","sources":["../../src/adapters/postgres.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export { createPostgresEventStore, type PostgresEventStoreConfig, type Serialize
|
|
|
4
4
|
export { createPostgresSnapshotStore, type PostgresSnapshotStoreConfig, } from "./postgres-snapshot-store.js";
|
|
5
5
|
export { postgres, type PostgresConfig } from "./postgres.js";
|
|
6
6
|
export { postgresTransactionManager } from "./postgres-transaction-manager.js";
|
|
7
|
+
export { type SessionTimeoutOptions, type ResolvedSessionTimeouts, resolveSessionTimeouts, applySessionTimeouts, } from "./session-timeouts.js";
|
|
7
8
|
export { createPostgresEventScheduler, type PostgresEventScheduler, type PostgresEventSchedulerConfig, } from "./postgres-event-scheduler.js";
|
|
8
9
|
export { bootstrapSchema, buildEventsTableDDL, buildEventsIndexesDDL, buildSnapshotsTableDDL, buildScheduledEventsTableDDL, buildScheduledEventsIndexesDDL, DEFAULT_TABLE_NAMES, type TableNames, } from "./schema.js";
|
|
9
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAWA,OAAO,EACL,oBAAoB,EACpB,6BAA6B,EAC7B,cAAc,GACf,MAAM,aAAa,CAAA;AAKpB,OAAO,EACL,cAAc,EACd,KAAK,eAAe,EACpB,KAAK,0BAA0B,EAC/B,KAAK,kBAAkB,EACvB,KAAK,QAAQ,GACd,MAAM,cAAc,CAAA;AAGrB,OAAO,EACL,wBAAwB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,UAAU,EACf,KAAK,WAAW,GACjB,MAAM,2BAA2B,CAAA;AAGlC,OAAO,EACL,2BAA2B,EAC3B,KAAK,2BAA2B,GACjC,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EAAE,QAAQ,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAA;AAM7D,OAAO,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAWA,OAAO,EACL,oBAAoB,EACpB,6BAA6B,EAC7B,cAAc,GACf,MAAM,aAAa,CAAA;AAKpB,OAAO,EACL,cAAc,EACd,KAAK,eAAe,EACpB,KAAK,0BAA0B,EAC/B,KAAK,kBAAkB,EACvB,KAAK,QAAQ,GACd,MAAM,cAAc,CAAA;AAGrB,OAAO,EACL,wBAAwB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,UAAU,EACf,KAAK,WAAW,GACjB,MAAM,2BAA2B,CAAA;AAGlC,OAAO,EACL,2BAA2B,EAC3B,KAAK,2BAA2B,GACjC,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EAAE,QAAQ,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAA;AAM7D,OAAO,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAA;AAK9E,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,uBAAuB,CAAA;AAM9B,OAAO,EACL,4BAA4B,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,4BAA4B,GAClC,MAAM,+BAA+B,CAAA;AAKtC,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,qBAAqB,EACrB,sBAAsB,EACtB,4BAA4B,EAC5B,8BAA8B,EAC9B,mBAAmB,EACnB,KAAK,UAAU,GAChB,MAAM,aAAa,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -24,6 +24,10 @@ export { postgres } from "./postgres.js";
|
|
|
24
24
|
// `postgres(config)`; exported for direct use when composing UoW runners by
|
|
25
25
|
// hand.
|
|
26
26
|
export { postgresTransactionManager } from "./postgres-transaction-manager.js";
|
|
27
|
+
// Per-transaction safety timeouts (idle-in-transaction / statement), armed by
|
|
28
|
+
// each adapter's transaction() at BEGIN. The options are spread onto every
|
|
29
|
+
// adapter config; the helpers are exported for authors of custom adapters.
|
|
30
|
+
export { resolveSessionTimeouts, applySessionTimeouts, } from "./session-timeouts.js";
|
|
27
31
|
// Postgres event scheduler — durable schedule() + cancel() + polling worker
|
|
28
32
|
// that fires due schedules into the event store. Wired into postgres()
|
|
29
33
|
// automatically when a uowFactory with the lazy postgres tx is in place;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,EAAE;AACF,oEAAoE;AACpE,6EAA6E;AAC7E,mEAAmE;AACnE,yEAAyE;AACzE,EAAE;AACF,2EAA2E;AAC3E,0DAA0D;AAC1D,gEAAgE;AAEhE,OAAO,EACL,oBAAoB,EACpB,6BAA6B,EAC7B,cAAc,GACf,MAAM,aAAa,CAAA;AAEpB,uDAAuD;AACvD,uEAAuE;AACvE,8CAA8C;AAC9C,OAAO,EACL,cAAc,GAKf,MAAM,cAAc,CAAA;AAErB,iDAAiD;AACjD,OAAO,EACL,wBAAwB,GAIzB,MAAM,2BAA2B,CAAA;AAElC,mCAAmC;AACnC,OAAO,EACL,2BAA2B,GAE5B,MAAM,8BAA8B,CAAA;AAErC,8BAA8B;AAC9B,OAAO,EAAE,QAAQ,EAAuB,MAAM,eAAe,CAAA;AAE7D,6EAA6E;AAC7E,6EAA6E;AAC7E,4EAA4E;AAC5E,QAAQ;AACR,OAAO,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAA;AAE9E,4EAA4E;AAC5E,uEAAuE;AACvE,yEAAyE;AACzE,yEAAyE;AACzE,OAAO,EACL,4BAA4B,GAG7B,MAAM,+BAA+B,CAAA;AAEtC,4EAA4E;AAC5E,2EAA2E;AAC3E,wDAAwD;AACxD,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,qBAAqB,EACrB,sBAAsB,EACtB,4BAA4B,EAC5B,8BAA8B,EAC9B,mBAAmB,GAEpB,MAAM,aAAa,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,EAAE;AACF,oEAAoE;AACpE,6EAA6E;AAC7E,mEAAmE;AACnE,yEAAyE;AACzE,EAAE;AACF,2EAA2E;AAC3E,0DAA0D;AAC1D,gEAAgE;AAEhE,OAAO,EACL,oBAAoB,EACpB,6BAA6B,EAC7B,cAAc,GACf,MAAM,aAAa,CAAA;AAEpB,uDAAuD;AACvD,uEAAuE;AACvE,8CAA8C;AAC9C,OAAO,EACL,cAAc,GAKf,MAAM,cAAc,CAAA;AAErB,iDAAiD;AACjD,OAAO,EACL,wBAAwB,GAIzB,MAAM,2BAA2B,CAAA;AAElC,mCAAmC;AACnC,OAAO,EACL,2BAA2B,GAE5B,MAAM,8BAA8B,CAAA;AAErC,8BAA8B;AAC9B,OAAO,EAAE,QAAQ,EAAuB,MAAM,eAAe,CAAA;AAE7D,6EAA6E;AAC7E,6EAA6E;AAC7E,4EAA4E;AAC5E,QAAQ;AACR,OAAO,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAA;AAE9E,8EAA8E;AAC9E,2EAA2E;AAC3E,2EAA2E;AAC3E,OAAO,EAGL,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,uBAAuB,CAAA;AAE9B,4EAA4E;AAC5E,uEAAuE;AACvE,yEAAyE;AACzE,yEAAyE;AACzE,OAAO,EACL,4BAA4B,GAG7B,MAAM,+BAA+B,CAAA;AAEtC,4EAA4E;AAC5E,2EAA2E;AAC3E,wDAAwD;AACxD,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,qBAAqB,EACrB,sBAAsB,EACtB,4BAA4B,EAC5B,8BAA8B,EAC9B,mBAAmB,GAEpB,MAAM,aAAa,CAAA"}
|
|
@@ -14,26 +14,7 @@
|
|
|
14
14
|
import { type TransactionManager } from "@kronos-ts/messaging";
|
|
15
15
|
import type { PostgresAdapter, PostgresAdapterTransaction } from "./adapter.js";
|
|
16
16
|
import { IsolationLevel } from "./adapter.js";
|
|
17
|
-
|
|
18
|
-
export interface PostgresTransactionManagerOptions {
|
|
19
|
-
/**
|
|
20
|
-
* `idle_in_transaction_session_timeout` (ms) applied via `SET LOCAL` on every
|
|
21
|
-
* transaction. A UoW that begins a tx but stalls before commit/rollback would
|
|
22
|
-
* otherwise hold its connection — and pin `pg_snapshot_xmin`, which gates the
|
|
23
|
-
* gap-free tailing query in the event store — open indefinitely, stalling all
|
|
24
|
-
* streaming processors until the process restarts. This bounds that window:
|
|
25
|
-
* postgres aborts the idle transaction and the connection (and xmin) is freed.
|
|
26
|
-
* Default 30000 (30s). Set 0 to disable (postgres default — no timeout).
|
|
27
|
-
*/
|
|
28
|
-
readonly idleInTransactionTimeoutMs?: number;
|
|
29
|
-
/**
|
|
30
|
-
* `statement_timeout` (ms) applied via `SET LOCAL` on every transaction.
|
|
31
|
-
* Bounds a single hung statement inside the tx. Default 0 (disabled) — large
|
|
32
|
-
* appends / replays can legitimately run long, so opt in per deployment.
|
|
33
|
-
*/
|
|
34
|
-
readonly statementTimeoutMs?: number;
|
|
35
|
-
}
|
|
36
|
-
export declare function postgresTransactionManager(adapter: PostgresAdapter, isolationLevel?: IsolationLevel, options?: PostgresTransactionManagerOptions): TransactionManager<PostgresAdapterTransaction>;
|
|
17
|
+
export declare function postgresTransactionManager(adapter: PostgresAdapter, isolationLevel?: IsolationLevel): TransactionManager<PostgresAdapterTransaction>;
|
|
37
18
|
/**
|
|
38
19
|
* Run `fn` inside a postgres tx, joining a UoW-scoped tx if one is active
|
|
39
20
|
* (or installed lazily), otherwise opening an ad-hoc tx via `adapter.transaction`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres-transaction-manager.d.ts","sourceRoot":"","sources":["../src/postgres-transaction-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAA+B,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAC3F,OAAO,KAAK,EAAE,eAAe,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAA;AAC/E,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAsB7C,
|
|
1
|
+
{"version":3,"file":"postgres-transaction-manager.d.ts","sourceRoot":"","sources":["../src/postgres-transaction-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAA+B,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAC3F,OAAO,KAAK,EAAE,eAAe,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAA;AAC/E,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAsB7C,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,eAAe,EACxB,cAAc,GAAE,cAA8C,GAC7D,kBAAkB,CAAC,0BAA0B,CAAC,CAuEhD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,iBAAiB,CAAC,CAAC,EACvC,OAAO,EAAE,eAAe,EACxB,EAAE,EAAE,CAAC,EAAE,EAAE,0BAA0B,KAAK,OAAO,CAAC,CAAC,CAAC,EAClD,cAAc,GAAE,cAA8C,GAC7D,OAAO,CAAC,CAAC,CAAC,CAIZ"}
|
|
@@ -21,22 +21,7 @@ import { IsolationLevel } from "./adapter.js";
|
|
|
21
21
|
const TX_CONTROL = Symbol("kronos.postgresTxControl");
|
|
22
22
|
/** Marker error: signals an intentional rollback so the .catch can suppress it. */
|
|
23
23
|
const ROLLBACK_MARKER = "__kronos_postgres_tx_rollback__";
|
|
24
|
-
|
|
25
|
-
export function postgresTransactionManager(adapter, isolationLevel = IsolationLevel.READ_COMMITTED, options = {}) {
|
|
26
|
-
const idleTimeoutMs = normalizeTimeoutMs(options.idleInTransactionTimeoutMs ?? DEFAULT_IDLE_IN_TRANSACTION_TIMEOUT_MS);
|
|
27
|
-
const statementTimeoutMs = normalizeTimeoutMs(options.statementTimeoutMs ?? 0);
|
|
28
|
-
// GUCs cannot be parameterized ($1) — the value is a config-supplied integer,
|
|
29
|
-
// normalized to a non-negative whole number, so inlining is injection-safe.
|
|
30
|
-
// SET LOCAL auto-resets at COMMIT/ROLLBACK, so it never leaks onto pooled
|
|
31
|
-
// connections.
|
|
32
|
-
async function applyTimeouts(tx) {
|
|
33
|
-
if (idleTimeoutMs > 0) {
|
|
34
|
-
await tx.query(`SET LOCAL idle_in_transaction_session_timeout = ${idleTimeoutMs}`);
|
|
35
|
-
}
|
|
36
|
-
if (statementTimeoutMs > 0) {
|
|
37
|
-
await tx.query(`SET LOCAL statement_timeout = ${statementTimeoutMs}`);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
24
|
+
export function postgresTransactionManager(adapter, isolationLevel = IsolationLevel.READ_COMMITTED) {
|
|
40
25
|
return {
|
|
41
26
|
async begin() {
|
|
42
27
|
let captureTx;
|
|
@@ -51,9 +36,9 @@ export function postgresTransactionManager(adapter, isolationLevel = IsolationLe
|
|
|
51
36
|
});
|
|
52
37
|
const txPromise = adapter
|
|
53
38
|
.transaction(isolationLevel, async (tx) => {
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
|
|
39
|
+
// Per-transaction safety timeouts are armed by the adapter's
|
|
40
|
+
// transaction() at BEGIN (see session-timeouts.ts), so they cover
|
|
41
|
+
// this UoW-scoped tx and every ad-hoc adapter.transaction() alike.
|
|
57
42
|
captureTx(tx);
|
|
58
43
|
await completion;
|
|
59
44
|
})
|
|
@@ -98,13 +83,6 @@ export function postgresTransactionManager(adapter, isolationLevel = IsolationLe
|
|
|
98
83
|
},
|
|
99
84
|
};
|
|
100
85
|
}
|
|
101
|
-
/** Coerce a config timeout to a non-negative whole number of milliseconds.
|
|
102
|
-
* Non-finite or negative values disable the timeout (treated as 0). */
|
|
103
|
-
function normalizeTimeoutMs(value) {
|
|
104
|
-
if (!Number.isFinite(value) || value <= 0)
|
|
105
|
-
return 0;
|
|
106
|
-
return Math.floor(value);
|
|
107
|
-
}
|
|
108
86
|
/**
|
|
109
87
|
* Run `fn` inside a postgres tx, joining a UoW-scoped tx if one is active
|
|
110
88
|
* (or installed lazily), otherwise opening an ad-hoc tx via `adapter.transaction`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres-transaction-manager.js","sourceRoot":"","sources":["../src/postgres-transaction-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,2BAA2B,EAA2B,MAAM,sBAAsB,CAAA;AAE3F,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAE7C;;;;GAIG;AACH,MAAM,UAAU,GAAG,MAAM,CAAC,0BAA0B,CAAC,CAAA;AAYrD,mFAAmF;AACnF,MAAM,eAAe,GAAG,iCAAiC,CAAA;
|
|
1
|
+
{"version":3,"file":"postgres-transaction-manager.js","sourceRoot":"","sources":["../src/postgres-transaction-manager.ts"],"names":[],"mappings":"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"}
|
package/dist/postgres.d.ts
CHANGED
|
@@ -46,14 +46,6 @@ export interface PostgresConfig {
|
|
|
46
46
|
readonly pollIntervalMs?: number;
|
|
47
47
|
readonly batchSize?: number;
|
|
48
48
|
};
|
|
49
|
-
/** Safety timeouts applied via `SET LOCAL` to every UoW-scoped transaction.
|
|
50
|
-
* Guards against a stalled UoW holding a connection — and pinning
|
|
51
|
-
* `pg_snapshot_xmin`, which would stall all streaming tailing — open until
|
|
52
|
-
* restart. Defaults: 30s idle-in-transaction, statement timeout disabled. */
|
|
53
|
-
readonly transaction?: {
|
|
54
|
-
readonly idleInTransactionTimeoutMs?: number;
|
|
55
|
-
readonly statementTimeoutMs?: number;
|
|
56
|
-
};
|
|
57
49
|
}
|
|
58
50
|
export declare function postgres(config: PostgresConfig): (app: App) => void;
|
|
59
51
|
//# sourceMappingURL=postgres.d.ts.map
|
package/dist/postgres.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../src/postgres.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAMzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAQnD,OAAO,EAAwC,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAEnF,MAAM,WAAW,cAAc;IAC7B,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;IACjC;uCACmC;IACnC,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAA;IAC5B,uEAAuE;IACvE,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAA;IAChC;4CACwC;IACxC,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAA;IAC/C,yDAAyD;IACzD,QAAQ,CAAC,SAAS,CAAC,EAAE;QACnB,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAA;QAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAC5B,CAAA;
|
|
1
|
+
{"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../src/postgres.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAMzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAQnD,OAAO,EAAwC,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAEnF,MAAM,WAAW,cAAc;IAC7B,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;IACjC;uCACmC;IACnC,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAA;IAC5B,uEAAuE;IACvE,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAA;IAChC;4CACwC;IACxC,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAA;IAC/C,yDAAyD;IACzD,QAAQ,CAAC,SAAS,CAAC,EAAE;QACnB,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAA;QAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAC5B,CAAA;CACF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAoEnE"}
|
package/dist/postgres.js
CHANGED
|
@@ -37,7 +37,11 @@ export function postgres(config) {
|
|
|
37
37
|
const { adapter, resilience } = config;
|
|
38
38
|
const bootstrap = config.bootstrap ?? true;
|
|
39
39
|
const tables = config.tableNames ?? DEFAULT_TABLE_NAMES;
|
|
40
|
-
|
|
40
|
+
// Safety timeouts (idle-in-transaction / statement) are armed by the adapter
|
|
41
|
+
// itself — configure them on the adapter (e.g. `pgAdapter({ connectionString,
|
|
42
|
+
// idleInTransactionTimeoutMs })`), so every transaction through it is bounded
|
|
43
|
+
// and two adapters on two databases stay independently configured.
|
|
44
|
+
const txManager = postgresTransactionManager(adapter);
|
|
41
45
|
return (app) => {
|
|
42
46
|
app.set("eventStore", ({ serializer, tagResolver }) => createPostgresEventStore({ adapter, serializer, tagResolver, tableNames: tables }));
|
|
43
47
|
app.set("snapshotStore", ({ serializer }) => createPostgresSnapshotStore({ adapter, serializer, tableNames: tables }));
|
package/dist/postgres.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres.js","sourceRoot":"","sources":["../src/postgres.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAIH,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAC7C,OAAO,EACL,kCAAkC,EAClC,WAAW,GACZ,MAAM,sBAAsB,CAAA;AAE7B,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAA;AACpE,OAAO,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAA;AAC1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAA;AAC9E,OAAO,EACL,4BAA4B,GAE7B,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAmB,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"postgres.js","sourceRoot":"","sources":["../src/postgres.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-transaction safety timeouts, armed via `SET LOCAL` by each adapter's
|
|
3
|
+
* `transaction()` at BEGIN. Living on the adapter (not the transaction
|
|
4
|
+
* manager) means EVERY postgres transaction is bounded — UoW-scoped commits,
|
|
5
|
+
* the event store's own-tx append/publish, and the scheduler worker tick alike
|
|
6
|
+
* — and each adapter instance carries its own settings, so two adapters
|
|
7
|
+
* pointed at two different databases stay fully decoupled.
|
|
8
|
+
*
|
|
9
|
+
* A non-postgres adapter (e.g. a future sqlite one) arms its own
|
|
10
|
+
* dialect-appropriate settings, or none.
|
|
11
|
+
*/
|
|
12
|
+
import type { PostgresAdapterTransaction } from "./adapter.js";
|
|
13
|
+
export interface SessionTimeoutOptions {
|
|
14
|
+
/**
|
|
15
|
+
* `idle_in_transaction_session_timeout` (ms) applied via `SET LOCAL` on every
|
|
16
|
+
* transaction. A transaction that begins but stalls before commit/rollback
|
|
17
|
+
* would otherwise hold its connection — and pin `pg_snapshot_xmin`, which
|
|
18
|
+
* gates the gap-free tailing query in the event store — open indefinitely,
|
|
19
|
+
* stalling all streaming processors until the process restarts. This bounds
|
|
20
|
+
* that window: postgres aborts the idle transaction and the connection (and
|
|
21
|
+
* xmin) is freed. Default 30000 (30s). Set 0 to disable (postgres default).
|
|
22
|
+
*/
|
|
23
|
+
readonly idleInTransactionTimeoutMs?: number;
|
|
24
|
+
/**
|
|
25
|
+
* `statement_timeout` (ms) applied via `SET LOCAL` on every transaction.
|
|
26
|
+
* Bounds a single hung statement inside the tx. Default 0 (disabled) — large
|
|
27
|
+
* appends / replays can legitimately run long, so opt in per deployment.
|
|
28
|
+
*/
|
|
29
|
+
readonly statementTimeoutMs?: number;
|
|
30
|
+
}
|
|
31
|
+
export interface ResolvedSessionTimeouts {
|
|
32
|
+
readonly idleInTransactionTimeoutMs: number;
|
|
33
|
+
readonly statementTimeoutMs: number;
|
|
34
|
+
}
|
|
35
|
+
/** Resolve config to concrete, normalized timeouts (applying defaults). */
|
|
36
|
+
export declare function resolveSessionTimeouts(opts?: SessionTimeoutOptions): ResolvedSessionTimeouts;
|
|
37
|
+
/**
|
|
38
|
+
* Arm the resolved timeouts on a freshly-opened transaction. No-op for any
|
|
39
|
+
* timeout resolved to 0.
|
|
40
|
+
*
|
|
41
|
+
* GUCs cannot be parameterized ($1) — the value is a config-supplied integer,
|
|
42
|
+
* normalized to a non-negative whole number, so inlining is injection-safe.
|
|
43
|
+
* `SET LOCAL` auto-resets at COMMIT/ROLLBACK, so it never leaks onto pooled
|
|
44
|
+
* connections.
|
|
45
|
+
*/
|
|
46
|
+
export declare function applySessionTimeouts(tx: PostgresAdapterTransaction, timeouts: ResolvedSessionTimeouts): Promise<void>;
|
|
47
|
+
//# sourceMappingURL=session-timeouts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-timeouts.d.ts","sourceRoot":"","sources":["../src/session-timeouts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAA;AAE9D,MAAM,WAAW,qBAAqB;IACpC;;;;;;;;OAQG;IACH,QAAQ,CAAC,0BAA0B,CAAC,EAAE,MAAM,CAAA;IAC5C;;;;OAIG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;CACrC;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,0BAA0B,EAAE,MAAM,CAAA;IAC3C,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAA;CACpC;AAID,2EAA2E;AAC3E,wBAAgB,sBAAsB,CAAC,IAAI,CAAC,EAAE,qBAAqB,GAAG,uBAAuB,CAO5F;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,0BAA0B,EAC9B,QAAQ,EAAE,uBAAuB,GAChC,OAAO,CAAC,IAAI,CAAC,CAOf"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-transaction safety timeouts, armed via `SET LOCAL` by each adapter's
|
|
3
|
+
* `transaction()` at BEGIN. Living on the adapter (not the transaction
|
|
4
|
+
* manager) means EVERY postgres transaction is bounded — UoW-scoped commits,
|
|
5
|
+
* the event store's own-tx append/publish, and the scheduler worker tick alike
|
|
6
|
+
* — and each adapter instance carries its own settings, so two adapters
|
|
7
|
+
* pointed at two different databases stay fully decoupled.
|
|
8
|
+
*
|
|
9
|
+
* A non-postgres adapter (e.g. a future sqlite one) arms its own
|
|
10
|
+
* dialect-appropriate settings, or none.
|
|
11
|
+
*/
|
|
12
|
+
const DEFAULT_IDLE_IN_TRANSACTION_TIMEOUT_MS = 30_000;
|
|
13
|
+
/** Resolve config to concrete, normalized timeouts (applying defaults). */
|
|
14
|
+
export function resolveSessionTimeouts(opts) {
|
|
15
|
+
return {
|
|
16
|
+
idleInTransactionTimeoutMs: normalizeTimeoutMs(opts?.idleInTransactionTimeoutMs ?? DEFAULT_IDLE_IN_TRANSACTION_TIMEOUT_MS),
|
|
17
|
+
statementTimeoutMs: normalizeTimeoutMs(opts?.statementTimeoutMs ?? 0),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Arm the resolved timeouts on a freshly-opened transaction. No-op for any
|
|
22
|
+
* timeout resolved to 0.
|
|
23
|
+
*
|
|
24
|
+
* GUCs cannot be parameterized ($1) — the value is a config-supplied integer,
|
|
25
|
+
* normalized to a non-negative whole number, so inlining is injection-safe.
|
|
26
|
+
* `SET LOCAL` auto-resets at COMMIT/ROLLBACK, so it never leaks onto pooled
|
|
27
|
+
* connections.
|
|
28
|
+
*/
|
|
29
|
+
export async function applySessionTimeouts(tx, timeouts) {
|
|
30
|
+
if (timeouts.idleInTransactionTimeoutMs > 0) {
|
|
31
|
+
await tx.query(`SET LOCAL idle_in_transaction_session_timeout = ${timeouts.idleInTransactionTimeoutMs}`);
|
|
32
|
+
}
|
|
33
|
+
if (timeouts.statementTimeoutMs > 0) {
|
|
34
|
+
await tx.query(`SET LOCAL statement_timeout = ${timeouts.statementTimeoutMs}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** Coerce a config timeout to a non-negative whole number of milliseconds.
|
|
38
|
+
* Non-finite or negative values disable the timeout (treated as 0). */
|
|
39
|
+
function normalizeTimeoutMs(value) {
|
|
40
|
+
if (!Number.isFinite(value) || value <= 0)
|
|
41
|
+
return 0;
|
|
42
|
+
return Math.floor(value);
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=session-timeouts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-timeouts.js","sourceRoot":"","sources":["../src/session-timeouts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AA4BH,MAAM,sCAAsC,GAAG,MAAM,CAAA;AAErD,2EAA2E;AAC3E,MAAM,UAAU,sBAAsB,CAAC,IAA4B;IACjE,OAAO;QACL,0BAA0B,EAAE,kBAAkB,CAC5C,IAAI,EAAE,0BAA0B,IAAI,sCAAsC,CAC3E;QACD,kBAAkB,EAAE,kBAAkB,CAAC,IAAI,EAAE,kBAAkB,IAAI,CAAC,CAAC;KACtE,CAAA;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,EAA8B,EAC9B,QAAiC;IAEjC,IAAI,QAAQ,CAAC,0BAA0B,GAAG,CAAC,EAAE,CAAC;QAC5C,MAAM,EAAE,CAAC,KAAK,CAAC,mDAAmD,QAAQ,CAAC,0BAA0B,EAAE,CAAC,CAAA;IAC1G,CAAC;IACD,IAAI,QAAQ,CAAC,kBAAkB,GAAG,CAAC,EAAE,CAAC;QACpC,MAAM,EAAE,CAAC,KAAK,CAAC,iCAAiC,QAAQ,CAAC,kBAAkB,EAAE,CAAC,CAAA;IAChF,CAAC;AACH,CAAC;AAED;wEACwE;AACxE,SAAS,kBAAkB,CAAC,KAAa;IACvC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,CAAC,CAAA;IACnD,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;AAC1B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kronos-ts/postgres",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "PostgreSQL extension for Kronos — event store and snapshot store adapters.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -68,9 +68,9 @@
|
|
|
68
68
|
},
|
|
69
69
|
"dependencies": {
|
|
70
70
|
"@kronos-ts/common": "0.1.1",
|
|
71
|
-
"@kronos-ts/app": "0.
|
|
72
|
-
"@kronos-ts/eventsourcing": "0.
|
|
73
|
-
"@kronos-ts/messaging": "0.
|
|
71
|
+
"@kronos-ts/app": "0.5.0",
|
|
72
|
+
"@kronos-ts/eventsourcing": "0.3.0",
|
|
73
|
+
"@kronos-ts/messaging": "0.8.0"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
76
|
"pg": ">=8.0.0",
|
package/src/adapters/bun-sql.ts
CHANGED
|
@@ -23,8 +23,13 @@ import type {
|
|
|
23
23
|
QueryRow,
|
|
24
24
|
} from "../adapter.js"
|
|
25
25
|
import { IsolationLevel } from "../adapter.js"
|
|
26
|
+
import {
|
|
27
|
+
type SessionTimeoutOptions,
|
|
28
|
+
applySessionTimeouts,
|
|
29
|
+
resolveSessionTimeouts,
|
|
30
|
+
} from "../session-timeouts.js"
|
|
26
31
|
|
|
27
|
-
export interface BunSqlAdapterConfig {
|
|
32
|
+
export interface BunSqlAdapterConfig extends SessionTimeoutOptions {
|
|
28
33
|
readonly connectionString: string
|
|
29
34
|
}
|
|
30
35
|
|
|
@@ -106,6 +111,7 @@ function getBunSql(): BunSqlConstructor {
|
|
|
106
111
|
export function bunSqlAdapter(config: BunSqlAdapterConfig): PostgresAdapter {
|
|
107
112
|
let sql: BunSqlInstance | undefined
|
|
108
113
|
let disconnected = false
|
|
114
|
+
const timeouts = resolveSessionTimeouts(config)
|
|
109
115
|
|
|
110
116
|
function getInstance(): BunSqlInstance {
|
|
111
117
|
if (!sql) {
|
|
@@ -183,6 +189,9 @@ export function bunSqlAdapter(config: BunSqlAdapterConfig): PostgresAdapter {
|
|
|
183
189
|
return txSql.unsafe(text, normalizeParams(params)).catch(normalizeBunSqlError) as Promise<R[]>
|
|
184
190
|
},
|
|
185
191
|
}
|
|
192
|
+
// Arm the per-transaction safety timeouts before handing the tx to the
|
|
193
|
+
// caller, so even the very first awaited statement is bounded.
|
|
194
|
+
await applySessionTimeouts(tx, timeouts)
|
|
186
195
|
return fn(tx)
|
|
187
196
|
}).catch(normalizeBunSqlError)
|
|
188
197
|
},
|
package/src/adapters/pg.ts
CHANGED
|
@@ -21,8 +21,13 @@ import type {
|
|
|
21
21
|
QueryRow,
|
|
22
22
|
} from "../adapter.js"
|
|
23
23
|
import { IsolationLevel } from "../adapter.js"
|
|
24
|
+
import {
|
|
25
|
+
type SessionTimeoutOptions,
|
|
26
|
+
applySessionTimeouts,
|
|
27
|
+
resolveSessionTimeouts,
|
|
28
|
+
} from "../session-timeouts.js"
|
|
24
29
|
|
|
25
|
-
export interface PgAdapterConfig {
|
|
30
|
+
export interface PgAdapterConfig extends SessionTimeoutOptions {
|
|
26
31
|
/** Standard libpq URI: postgresql://user:pass@host:port/db */
|
|
27
32
|
readonly connectionString: string
|
|
28
33
|
/** Optional pg.Pool config overrides (max connections, idleTimeoutMillis, etc.). */
|
|
@@ -39,6 +44,7 @@ export function pgAdapter(config: PgAdapterConfig): PostgresAdapter {
|
|
|
39
44
|
let listenClient: PoolClient | undefined
|
|
40
45
|
const listenSlots = new Map<string, Set<ListenerSlot>>()
|
|
41
46
|
let disconnected = false
|
|
47
|
+
const timeouts = resolveSessionTimeouts(config)
|
|
42
48
|
|
|
43
49
|
function getPool(): Pool {
|
|
44
50
|
if (!pool) {
|
|
@@ -132,6 +138,9 @@ export function pgAdapter(config: PgAdapterConfig): PostgresAdapter {
|
|
|
132
138
|
}
|
|
133
139
|
let result: T
|
|
134
140
|
try {
|
|
141
|
+
// Arm the per-transaction safety timeouts before handing the tx to
|
|
142
|
+
// the caller, so even the very first awaited statement is bounded.
|
|
143
|
+
await applySessionTimeouts(tx, timeouts)
|
|
135
144
|
result = await fn(tx)
|
|
136
145
|
} catch (err) {
|
|
137
146
|
// ROLLBACK best-effort; preserve the ORIGINAL error.
|
package/src/adapters/postgres.ts
CHANGED
|
@@ -26,8 +26,13 @@ import type {
|
|
|
26
26
|
QueryRow,
|
|
27
27
|
} from "../adapter.js"
|
|
28
28
|
import { IsolationLevel } from "../adapter.js"
|
|
29
|
+
import {
|
|
30
|
+
type SessionTimeoutOptions,
|
|
31
|
+
applySessionTimeouts,
|
|
32
|
+
resolveSessionTimeouts,
|
|
33
|
+
} from "../session-timeouts.js"
|
|
29
34
|
|
|
30
|
-
export interface PostgresAdapterConfig {
|
|
35
|
+
export interface PostgresAdapterConfig extends SessionTimeoutOptions {
|
|
31
36
|
readonly connectionString: string
|
|
32
37
|
/** Additional postgres.js options. `transform.column.from` is forced off regardless. */
|
|
33
38
|
readonly clientOptions?: Parameters<typeof postgresClient>[1]
|
|
@@ -36,6 +41,7 @@ export interface PostgresAdapterConfig {
|
|
|
36
41
|
export function postgresAdapter(config: PostgresAdapterConfig): PostgresAdapter {
|
|
37
42
|
let sql: Sql | undefined
|
|
38
43
|
let disconnected = false
|
|
44
|
+
const timeouts = resolveSessionTimeouts(config)
|
|
39
45
|
|
|
40
46
|
function getSql(): Sql {
|
|
41
47
|
if (!sql) {
|
|
@@ -112,6 +118,9 @@ export function postgresAdapter(config: PostgresAdapterConfig): PostgresAdapter
|
|
|
112
118
|
return rows
|
|
113
119
|
},
|
|
114
120
|
}
|
|
121
|
+
// Arm the per-transaction safety timeouts before handing the tx to the
|
|
122
|
+
// caller, so even the very first awaited statement is bounded.
|
|
123
|
+
await applySessionTimeouts(tx, timeouts)
|
|
115
124
|
return fn(tx)
|
|
116
125
|
})) as T
|
|
117
126
|
},
|
package/src/index.ts
CHANGED
|
@@ -49,6 +49,16 @@ export { postgres, type PostgresConfig } from "./postgres.js"
|
|
|
49
49
|
// hand.
|
|
50
50
|
export { postgresTransactionManager } from "./postgres-transaction-manager.js"
|
|
51
51
|
|
|
52
|
+
// Per-transaction safety timeouts (idle-in-transaction / statement), armed by
|
|
53
|
+
// each adapter's transaction() at BEGIN. The options are spread onto every
|
|
54
|
+
// adapter config; the helpers are exported for authors of custom adapters.
|
|
55
|
+
export {
|
|
56
|
+
type SessionTimeoutOptions,
|
|
57
|
+
type ResolvedSessionTimeouts,
|
|
58
|
+
resolveSessionTimeouts,
|
|
59
|
+
applySessionTimeouts,
|
|
60
|
+
} from "./session-timeouts.js"
|
|
61
|
+
|
|
52
62
|
// Postgres event scheduler — durable schedule() + cancel() + polling worker
|
|
53
63
|
// that fires due schedules into the event store. Wired into postgres()
|
|
54
64
|
// automatically when a uowFactory with the lazy postgres tx is in place;
|
|
@@ -36,51 +36,10 @@ interface ManagedPostgresTransaction extends PostgresAdapterTransaction {
|
|
|
36
36
|
/** Marker error: signals an intentional rollback so the .catch can suppress it. */
|
|
37
37
|
const ROLLBACK_MARKER = "__kronos_postgres_tx_rollback__"
|
|
38
38
|
|
|
39
|
-
/** Tuning for the safety timeouts applied to every UoW-scoped transaction. */
|
|
40
|
-
export interface PostgresTransactionManagerOptions {
|
|
41
|
-
/**
|
|
42
|
-
* `idle_in_transaction_session_timeout` (ms) applied via `SET LOCAL` on every
|
|
43
|
-
* transaction. A UoW that begins a tx but stalls before commit/rollback would
|
|
44
|
-
* otherwise hold its connection — and pin `pg_snapshot_xmin`, which gates the
|
|
45
|
-
* gap-free tailing query in the event store — open indefinitely, stalling all
|
|
46
|
-
* streaming processors until the process restarts. This bounds that window:
|
|
47
|
-
* postgres aborts the idle transaction and the connection (and xmin) is freed.
|
|
48
|
-
* Default 30000 (30s). Set 0 to disable (postgres default — no timeout).
|
|
49
|
-
*/
|
|
50
|
-
readonly idleInTransactionTimeoutMs?: number
|
|
51
|
-
/**
|
|
52
|
-
* `statement_timeout` (ms) applied via `SET LOCAL` on every transaction.
|
|
53
|
-
* Bounds a single hung statement inside the tx. Default 0 (disabled) — large
|
|
54
|
-
* appends / replays can legitimately run long, so opt in per deployment.
|
|
55
|
-
*/
|
|
56
|
-
readonly statementTimeoutMs?: number
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const DEFAULT_IDLE_IN_TRANSACTION_TIMEOUT_MS = 30_000
|
|
60
|
-
|
|
61
39
|
export function postgresTransactionManager(
|
|
62
40
|
adapter: PostgresAdapter,
|
|
63
41
|
isolationLevel: IsolationLevel = IsolationLevel.READ_COMMITTED,
|
|
64
|
-
options: PostgresTransactionManagerOptions = {},
|
|
65
42
|
): TransactionManager<PostgresAdapterTransaction> {
|
|
66
|
-
const idleTimeoutMs = normalizeTimeoutMs(
|
|
67
|
-
options.idleInTransactionTimeoutMs ?? DEFAULT_IDLE_IN_TRANSACTION_TIMEOUT_MS,
|
|
68
|
-
)
|
|
69
|
-
const statementTimeoutMs = normalizeTimeoutMs(options.statementTimeoutMs ?? 0)
|
|
70
|
-
|
|
71
|
-
// GUCs cannot be parameterized ($1) — the value is a config-supplied integer,
|
|
72
|
-
// normalized to a non-negative whole number, so inlining is injection-safe.
|
|
73
|
-
// SET LOCAL auto-resets at COMMIT/ROLLBACK, so it never leaks onto pooled
|
|
74
|
-
// connections.
|
|
75
|
-
async function applyTimeouts(tx: PostgresAdapterTransaction): Promise<void> {
|
|
76
|
-
if (idleTimeoutMs > 0) {
|
|
77
|
-
await tx.query(`SET LOCAL idle_in_transaction_session_timeout = ${idleTimeoutMs}`)
|
|
78
|
-
}
|
|
79
|
-
if (statementTimeoutMs > 0) {
|
|
80
|
-
await tx.query(`SET LOCAL statement_timeout = ${statementTimeoutMs}`)
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
43
|
return {
|
|
85
44
|
async begin(): Promise<PostgresAdapterTransaction> {
|
|
86
45
|
let captureTx!: (tx: PostgresAdapterTransaction) => void
|
|
@@ -97,9 +56,9 @@ export function postgresTransactionManager(
|
|
|
97
56
|
|
|
98
57
|
const txPromise = adapter
|
|
99
58
|
.transaction(isolationLevel, async (tx) => {
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
|
|
59
|
+
// Per-transaction safety timeouts are armed by the adapter's
|
|
60
|
+
// transaction() at BEGIN (see session-timeouts.ts), so they cover
|
|
61
|
+
// this UoW-scoped tx and every ad-hoc adapter.transaction() alike.
|
|
103
62
|
captureTx(tx)
|
|
104
63
|
await completion
|
|
105
64
|
})
|
|
@@ -153,13 +112,6 @@ export function postgresTransactionManager(
|
|
|
153
112
|
}
|
|
154
113
|
}
|
|
155
114
|
|
|
156
|
-
/** Coerce a config timeout to a non-negative whole number of milliseconds.
|
|
157
|
-
* Non-finite or negative values disable the timeout (treated as 0). */
|
|
158
|
-
function normalizeTimeoutMs(value: number): number {
|
|
159
|
-
if (!Number.isFinite(value) || value <= 0) return 0
|
|
160
|
-
return Math.floor(value)
|
|
161
|
-
}
|
|
162
|
-
|
|
163
115
|
/**
|
|
164
116
|
* Run `fn` inside a postgres tx, joining a UoW-scoped tx if one is active
|
|
165
117
|
* (or installed lazily), otherwise opening an ad-hoc tx via `adapter.transaction`.
|
package/src/postgres.ts
CHANGED
|
@@ -60,14 +60,6 @@ export interface PostgresConfig {
|
|
|
60
60
|
readonly pollIntervalMs?: number
|
|
61
61
|
readonly batchSize?: number
|
|
62
62
|
}
|
|
63
|
-
/** Safety timeouts applied via `SET LOCAL` to every UoW-scoped transaction.
|
|
64
|
-
* Guards against a stalled UoW holding a connection — and pinning
|
|
65
|
-
* `pg_snapshot_xmin`, which would stall all streaming tailing — open until
|
|
66
|
-
* restart. Defaults: 30s idle-in-transaction, statement timeout disabled. */
|
|
67
|
-
readonly transaction?: {
|
|
68
|
-
readonly idleInTransactionTimeoutMs?: number
|
|
69
|
-
readonly statementTimeoutMs?: number
|
|
70
|
-
}
|
|
71
63
|
}
|
|
72
64
|
|
|
73
65
|
export function postgres(config: PostgresConfig): (app: App) => void {
|
|
@@ -75,7 +67,11 @@ export function postgres(config: PostgresConfig): (app: App) => void {
|
|
|
75
67
|
const bootstrap = config.bootstrap ?? true
|
|
76
68
|
const tables = config.tableNames ?? DEFAULT_TABLE_NAMES
|
|
77
69
|
|
|
78
|
-
|
|
70
|
+
// Safety timeouts (idle-in-transaction / statement) are armed by the adapter
|
|
71
|
+
// itself — configure them on the adapter (e.g. `pgAdapter({ connectionString,
|
|
72
|
+
// idleInTransactionTimeoutMs })`), so every transaction through it is bounded
|
|
73
|
+
// and two adapters on two databases stay independently configured.
|
|
74
|
+
const txManager = postgresTransactionManager(adapter)
|
|
79
75
|
|
|
80
76
|
return (app: App) => {
|
|
81
77
|
app.set("eventStore", ({ serializer, tagResolver }) =>
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-transaction safety timeouts, armed via `SET LOCAL` by each adapter's
|
|
3
|
+
* `transaction()` at BEGIN. Living on the adapter (not the transaction
|
|
4
|
+
* manager) means EVERY postgres transaction is bounded — UoW-scoped commits,
|
|
5
|
+
* the event store's own-tx append/publish, and the scheduler worker tick alike
|
|
6
|
+
* — and each adapter instance carries its own settings, so two adapters
|
|
7
|
+
* pointed at two different databases stay fully decoupled.
|
|
8
|
+
*
|
|
9
|
+
* A non-postgres adapter (e.g. a future sqlite one) arms its own
|
|
10
|
+
* dialect-appropriate settings, or none.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { PostgresAdapterTransaction } from "./adapter.js"
|
|
14
|
+
|
|
15
|
+
export interface SessionTimeoutOptions {
|
|
16
|
+
/**
|
|
17
|
+
* `idle_in_transaction_session_timeout` (ms) applied via `SET LOCAL` on every
|
|
18
|
+
* transaction. A transaction that begins but stalls before commit/rollback
|
|
19
|
+
* would otherwise hold its connection — and pin `pg_snapshot_xmin`, which
|
|
20
|
+
* gates the gap-free tailing query in the event store — open indefinitely,
|
|
21
|
+
* stalling all streaming processors until the process restarts. This bounds
|
|
22
|
+
* that window: postgres aborts the idle transaction and the connection (and
|
|
23
|
+
* xmin) is freed. Default 30000 (30s). Set 0 to disable (postgres default).
|
|
24
|
+
*/
|
|
25
|
+
readonly idleInTransactionTimeoutMs?: number
|
|
26
|
+
/**
|
|
27
|
+
* `statement_timeout` (ms) applied via `SET LOCAL` on every transaction.
|
|
28
|
+
* Bounds a single hung statement inside the tx. Default 0 (disabled) — large
|
|
29
|
+
* appends / replays can legitimately run long, so opt in per deployment.
|
|
30
|
+
*/
|
|
31
|
+
readonly statementTimeoutMs?: number
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface ResolvedSessionTimeouts {
|
|
35
|
+
readonly idleInTransactionTimeoutMs: number
|
|
36
|
+
readonly statementTimeoutMs: number
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const DEFAULT_IDLE_IN_TRANSACTION_TIMEOUT_MS = 30_000
|
|
40
|
+
|
|
41
|
+
/** Resolve config to concrete, normalized timeouts (applying defaults). */
|
|
42
|
+
export function resolveSessionTimeouts(opts?: SessionTimeoutOptions): ResolvedSessionTimeouts {
|
|
43
|
+
return {
|
|
44
|
+
idleInTransactionTimeoutMs: normalizeTimeoutMs(
|
|
45
|
+
opts?.idleInTransactionTimeoutMs ?? DEFAULT_IDLE_IN_TRANSACTION_TIMEOUT_MS,
|
|
46
|
+
),
|
|
47
|
+
statementTimeoutMs: normalizeTimeoutMs(opts?.statementTimeoutMs ?? 0),
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Arm the resolved timeouts on a freshly-opened transaction. No-op for any
|
|
53
|
+
* timeout resolved to 0.
|
|
54
|
+
*
|
|
55
|
+
* GUCs cannot be parameterized ($1) — the value is a config-supplied integer,
|
|
56
|
+
* normalized to a non-negative whole number, so inlining is injection-safe.
|
|
57
|
+
* `SET LOCAL` auto-resets at COMMIT/ROLLBACK, so it never leaks onto pooled
|
|
58
|
+
* connections.
|
|
59
|
+
*/
|
|
60
|
+
export async function applySessionTimeouts(
|
|
61
|
+
tx: PostgresAdapterTransaction,
|
|
62
|
+
timeouts: ResolvedSessionTimeouts,
|
|
63
|
+
): Promise<void> {
|
|
64
|
+
if (timeouts.idleInTransactionTimeoutMs > 0) {
|
|
65
|
+
await tx.query(`SET LOCAL idle_in_transaction_session_timeout = ${timeouts.idleInTransactionTimeoutMs}`)
|
|
66
|
+
}
|
|
67
|
+
if (timeouts.statementTimeoutMs > 0) {
|
|
68
|
+
await tx.query(`SET LOCAL statement_timeout = ${timeouts.statementTimeoutMs}`)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Coerce a config timeout to a non-negative whole number of milliseconds.
|
|
73
|
+
* Non-finite or negative values disable the timeout (treated as 0). */
|
|
74
|
+
function normalizeTimeoutMs(value: number): number {
|
|
75
|
+
if (!Number.isFinite(value) || value <= 0) return 0
|
|
76
|
+
return Math.floor(value)
|
|
77
|
+
}
|