@pattern-stack/codegen 0.17.1 → 0.17.2
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/CHANGELOG.md +36 -0
- package/dist/{chunk-HPS554L4.js → chunk-235ZMMJR.js} +6 -6
- package/dist/{chunk-BK5ICA2F.js → chunk-4MVGAMUA.js} +4 -4
- package/dist/{chunk-SFQRETXJ.js → chunk-65MO75WM.js} +9 -9
- package/dist/{chunk-5RT7JGKT.js → chunk-7OVCARTQ.js} +4 -4
- package/dist/{chunk-JA7GJDNI.js → chunk-ATVGYF3D.js} +7 -7
- package/dist/{chunk-HOIRY5XP.js → chunk-AZLUWG5S.js} +9 -9
- package/dist/{chunk-4PFF3ED4.js → chunk-B34G6PHD.js} +10 -10
- package/dist/{chunk-W2UIDI3R.js → chunk-CLWBNXKF.js} +4 -4
- package/dist/{chunk-FVNAU7VO.js → chunk-E6PLM6QG.js} +8 -8
- package/dist/{chunk-43SBT72G.js → chunk-I6UXRJ3Q.js} +4 -4
- package/dist/{chunk-PSDVGPQR.js → chunk-KZDHMZ45.js} +5 -5
- package/dist/{chunk-EJBK7I4F.js → chunk-OZEPJGMA.js} +3 -3
- package/dist/{chunk-MYQIQ27N.js → chunk-Q6LRJ4VI.js} +51 -2
- package/dist/chunk-Q6LRJ4VI.js.map +1 -0
- package/dist/{chunk-SGSWVNNB.js → chunk-R6F6KFIL.js} +7 -7
- package/dist/{chunk-FWRL7BZ5.js → chunk-VDL5CJ5C.js} +26 -16
- package/dist/chunk-VDL5CJ5C.js.map +1 -0
- package/dist/{chunk-DUMI2J5M.js → chunk-VQOAATIG.js} +4 -4
- package/dist/{chunk-E45CSC33.js → chunk-XKWOJZZ4.js} +2 -2
- package/dist/{chunk-LQ6PYFU6.js → chunk-Z7PQCAVK.js} +4 -4
- package/dist/runtime/base-classes/index.js +24 -24
- package/dist/runtime/shared/openapi/index.js +3 -3
- package/dist/runtime/subsystems/auth/auth.module.js +1 -1
- package/dist/runtime/subsystems/auth/index.js +8 -8
- package/dist/runtime/subsystems/bridge/bridge-delivery-handler.js +3 -3
- package/dist/runtime/subsystems/bridge/bridge-delivery.drizzle-backend.js +1 -1
- package/dist/runtime/subsystems/bridge/bridge-outbox-drain-hook.js +6 -6
- package/dist/runtime/subsystems/bridge/bridge.module.js +15 -15
- package/dist/runtime/subsystems/bridge/event-flow.service.js +2 -2
- package/dist/runtime/subsystems/bridge/index.js +15 -15
- package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js +4 -4
- package/dist/runtime/subsystems/events/event-bus.memory-backend.js +2 -2
- package/dist/runtime/subsystems/events/events.module.js +6 -6
- package/dist/runtime/subsystems/events/index.js +9 -9
- package/dist/runtime/subsystems/index.js +70 -70
- package/dist/runtime/subsystems/integration/build-change-source.js +2 -2
- package/dist/runtime/subsystems/integration/index.js +30 -30
- package/dist/runtime/subsystems/integration/integration.module.js +4 -4
- package/dist/runtime/subsystems/jobs/index.js +23 -23
- package/dist/runtime/subsystems/jobs/job-orchestrator.bullmq-backend.js +3 -3
- package/dist/runtime/subsystems/jobs/job-orchestrator.drizzle-backend.js +3 -3
- package/dist/runtime/subsystems/jobs/job-orchestrator.memory-backend.js +2 -2
- package/dist/runtime/subsystems/jobs/job-worker.d.ts +8 -0
- package/dist/runtime/subsystems/jobs/job-worker.js +3 -3
- package/dist/runtime/subsystems/jobs/job-worker.module.js +9 -9
- package/dist/runtime/subsystems/jobs/jobs-domain.module.js +7 -7
- package/dist/runtime/subsystems/jobs/pg-notify.d.ts +25 -1
- package/dist/runtime/subsystems/jobs/pg-notify.js +1 -1
- package/dist/runtime/subsystems/observability/index.js +3 -3
- package/dist/runtime/subsystems/observability/observability.module.js +3 -3
- package/dist/runtime/subsystems/observability/observability.service.js +2 -2
- package/dist/runtime/subsystems/storage/index.js +4 -4
- package/dist/runtime/subsystems/storage/storage.module.js +2 -2
- package/dist/src/cli/index.js +11 -11
- package/dist/src/index.js +9 -9
- package/package.json +1 -1
- package/runtime/subsystems/jobs/job-worker.ts +29 -11
- package/runtime/subsystems/jobs/pg-notify.ts +63 -3
- package/dist/chunk-FWRL7BZ5.js.map +0 -1
- package/dist/chunk-MYQIQ27N.js.map +0 -1
- /package/dist/{chunk-HPS554L4.js.map → chunk-235ZMMJR.js.map} +0 -0
- /package/dist/{chunk-BK5ICA2F.js.map → chunk-4MVGAMUA.js.map} +0 -0
- /package/dist/{chunk-SFQRETXJ.js.map → chunk-65MO75WM.js.map} +0 -0
- /package/dist/{chunk-5RT7JGKT.js.map → chunk-7OVCARTQ.js.map} +0 -0
- /package/dist/{chunk-JA7GJDNI.js.map → chunk-ATVGYF3D.js.map} +0 -0
- /package/dist/{chunk-HOIRY5XP.js.map → chunk-AZLUWG5S.js.map} +0 -0
- /package/dist/{chunk-4PFF3ED4.js.map → chunk-B34G6PHD.js.map} +0 -0
- /package/dist/{chunk-W2UIDI3R.js.map → chunk-CLWBNXKF.js.map} +0 -0
- /package/dist/{chunk-FVNAU7VO.js.map → chunk-E6PLM6QG.js.map} +0 -0
- /package/dist/{chunk-43SBT72G.js.map → chunk-I6UXRJ3Q.js.map} +0 -0
- /package/dist/{chunk-PSDVGPQR.js.map → chunk-KZDHMZ45.js.map} +0 -0
- /package/dist/{chunk-EJBK7I4F.js.map → chunk-OZEPJGMA.js.map} +0 -0
- /package/dist/{chunk-SGSWVNNB.js.map → chunk-R6F6KFIL.js.map} +0 -0
- /package/dist/{chunk-DUMI2J5M.js.map → chunk-VQOAATIG.js.map} +0 -0
- /package/dist/{chunk-E45CSC33.js.map → chunk-XKWOJZZ4.js.map} +0 -0
- /package/dist/{chunk-LQ6PYFU6.js.map → chunk-Z7PQCAVK.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,42 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.17.2] — 2026-06-04
|
|
8
|
+
|
|
9
|
+
**Shutdown leak fix** (LISTEN-NOTIFY-2; swe-brain dogfood). With
|
|
10
|
+
`listen_notify: true` (the LISTEN/NOTIFY wake extension shipped in 0.16.0), a
|
|
11
|
+
Nest app that booted and then `app.close()`d — e.g. a boot-check / CI smoke step —
|
|
12
|
+
never exited: at least one `LISTEN codegen_jobs_wake` client survived
|
|
13
|
+
`app.close()`, holding an ESTABLISHED Postgres socket open forever (two swe-brain
|
|
14
|
+
CI runs hung for hours). Backward-compatible; affects only consumers that opted
|
|
15
|
+
into `listen_notify`.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- **`PgNotifyListener.stop()` is race-safe against an in-flight `connect()`**
|
|
20
|
+
(LISTEN-NOTIFY-2 RC1 — the defect that actually fired). `connect()` checked
|
|
21
|
+
`this.stopped` only at entry, then `await pool.connect()`, wired handlers,
|
|
22
|
+
issued `LISTEN`, and assigned `this.client` last. A `stop()` arriving during
|
|
23
|
+
the checkout await ran `releaseClient()` against a still-null `this.client`
|
|
24
|
+
(released nothing); the resuming `connect()` then assigned the client and
|
|
25
|
+
issued `LISTEN` — leaking a checked-out connection with no owner left to
|
|
26
|
+
release it. With 5–6 listeners (one per jobs pool + the events drainer) all
|
|
27
|
+
starting at bootstrap and a tight `app.close()`, the race fired on ~1 of 6
|
|
28
|
+
listeners — exactly the observed signature (one survivor, the rest clean).
|
|
29
|
+
Now `connect()` re-checks `stopped` after the checkout AND after `LISTEN`,
|
|
30
|
+
destroying the just-acquired client and bailing before assignment; `stop()`
|
|
31
|
+
tracks and awaits the in-flight connect promise before its own release, so
|
|
32
|
+
`app.close()` can't return while a checkout is still mid-flight. Releases use
|
|
33
|
+
`release(true)` (destroy) so a half-listening socket is never reused.
|
|
34
|
+
- **`JobWorker.onModuleDestroy` stops the wake listener on EVERY destroy path**
|
|
35
|
+
(LISTEN-NOTIFY-2 RC2 — latent). The listener `stop()` lived only on the first
|
|
36
|
+
(non-`shuttingDown`) branch, so a SIGTERM-then-Nest double-destroy hit the
|
|
37
|
+
`if (this.shuttingDown) { …; return; }` early return and skipped it, leaking
|
|
38
|
+
the listener under the normal SIGTERM shutdown path. Teardown is now an
|
|
39
|
+
idempotent `stopNotifyListener()` called unconditionally at the top of every
|
|
40
|
+
destroy. `DrizzleEventBus` already stopped its listener unconditionally; it
|
|
41
|
+
shared `PgNotifyListener` and so benefits from the RC1 fix directly.
|
|
42
|
+
|
|
7
43
|
## [0.17.1] — 2026-06-04
|
|
8
44
|
|
|
9
45
|
**Two dogfood fixes that bit the same swe-brain mutation drain** (ADR-0009
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
JobWorker
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-VDL5CJ5C.js";
|
|
4
4
|
import {
|
|
5
5
|
JobsDomainModule
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-AZLUWG5S.js";
|
|
7
7
|
import {
|
|
8
8
|
BootValidationError,
|
|
9
9
|
ReservedPoolViolationError
|
|
@@ -18,14 +18,14 @@ import {
|
|
|
18
18
|
allPoolNames,
|
|
19
19
|
loadPoolConfig
|
|
20
20
|
} from "./chunk-RHVN6NA7.js";
|
|
21
|
+
import {
|
|
22
|
+
HandlerRegistry
|
|
23
|
+
} from "./chunk-7P5ODGLA.js";
|
|
21
24
|
import {
|
|
22
25
|
JOB_ORCHESTRATOR,
|
|
23
26
|
JOB_RUN_SERVICE,
|
|
24
27
|
JOB_STEP_SERVICE
|
|
25
28
|
} from "./chunk-ZPL74UQN.js";
|
|
26
|
-
import {
|
|
27
|
-
HandlerRegistry
|
|
28
|
-
} from "./chunk-7P5ODGLA.js";
|
|
29
29
|
import {
|
|
30
30
|
tokenKey
|
|
31
31
|
} from "./chunk-GYGNEQSC.js";
|
|
@@ -290,4 +290,4 @@ export {
|
|
|
290
290
|
JobWorkerOrchestrator,
|
|
291
291
|
JobWorkerModule
|
|
292
292
|
};
|
|
293
|
-
//# sourceMappingURL=chunk-
|
|
293
|
+
//# sourceMappingURL=chunk-235ZMMJR.js.map
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
STORAGE
|
|
3
|
-
} from "./chunk-NYBCQZC7.js";
|
|
4
1
|
import {
|
|
5
2
|
LocalStorageBackend
|
|
6
3
|
} from "./chunk-JWNHNUYL.js";
|
|
7
4
|
import {
|
|
8
5
|
MemoryStorageBackend
|
|
9
6
|
} from "./chunk-3SZFUTXE.js";
|
|
7
|
+
import {
|
|
8
|
+
STORAGE
|
|
9
|
+
} from "./chunk-NYBCQZC7.js";
|
|
10
10
|
import {
|
|
11
11
|
__decorateClass
|
|
12
12
|
} from "./chunk-2E224ZSN.js";
|
|
@@ -37,4 +37,4 @@ StorageModule = __decorateClass([
|
|
|
37
37
|
export {
|
|
38
38
|
StorageModule
|
|
39
39
|
};
|
|
40
|
-
//# sourceMappingURL=chunk-
|
|
40
|
+
//# sourceMappingURL=chunk-4MVGAMUA.js.map
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BRIDGE_DELIVERY_JOB_TYPE
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-R6F6KFIL.js";
|
|
4
4
|
import {
|
|
5
5
|
bridgeDelivery
|
|
6
6
|
} from "./chunk-2TVVBC53.js";
|
|
7
|
-
import {
|
|
8
|
-
JOBS_LISTEN_NOTIFY
|
|
9
|
-
} from "./chunk-ZPL74UQN.js";
|
|
10
|
-
import {
|
|
11
|
-
jobRuns
|
|
12
|
-
} from "./chunk-OKXZ63IA.js";
|
|
13
7
|
import {
|
|
14
8
|
JOBS_WAKE_CHANNEL,
|
|
15
9
|
pgNotify
|
|
16
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-Q6LRJ4VI.js";
|
|
11
|
+
import {
|
|
12
|
+
JOBS_LISTEN_NOTIFY
|
|
13
|
+
} from "./chunk-ZPL74UQN.js";
|
|
17
14
|
import {
|
|
18
15
|
BRIDGE_REGISTRY
|
|
19
16
|
} from "./chunk-4LH67P4U.js";
|
|
17
|
+
import {
|
|
18
|
+
jobRuns
|
|
19
|
+
} from "./chunk-OKXZ63IA.js";
|
|
20
20
|
import {
|
|
21
21
|
__decorateClass,
|
|
22
22
|
__decorateParam
|
|
@@ -151,4 +151,4 @@ BridgeOutboxDrainHook = __decorateClass([
|
|
|
151
151
|
export {
|
|
152
152
|
BridgeOutboxDrainHook
|
|
153
153
|
};
|
|
154
|
-
//# sourceMappingURL=chunk-
|
|
154
|
+
//# sourceMappingURL=chunk-65MO75WM.js.map
|
|
@@ -4,14 +4,14 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
JOB_ORCHESTRATOR
|
|
6
6
|
} from "./chunk-ZPL74UQN.js";
|
|
7
|
+
import {
|
|
8
|
+
EVENT_BUS
|
|
9
|
+
} from "./chunk-H5NH7KPE.js";
|
|
7
10
|
import {
|
|
8
11
|
BRIDGE_DELIVERY_REPO,
|
|
9
12
|
BRIDGE_MULTI_TENANT,
|
|
10
13
|
BRIDGE_REGISTRY
|
|
11
14
|
} from "./chunk-4LH67P4U.js";
|
|
12
|
-
import {
|
|
13
|
-
EVENT_BUS
|
|
14
|
-
} from "./chunk-H5NH7KPE.js";
|
|
15
15
|
import {
|
|
16
16
|
DRIZZLE
|
|
17
17
|
} from "./chunk-U64T4YZE.js";
|
|
@@ -106,4 +106,4 @@ EventFlowService = __decorateClass([
|
|
|
106
106
|
export {
|
|
107
107
|
EventFlowService
|
|
108
108
|
};
|
|
109
|
-
//# sourceMappingURL=chunk-
|
|
109
|
+
//# sourceMappingURL=chunk-7OVCARTQ.js.map
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
MemoryCursorStore
|
|
3
|
-
} from "./chunk-AHV4GDYM.js";
|
|
4
1
|
import {
|
|
5
2
|
DrizzleIntegrationRunRecorder
|
|
6
3
|
} from "./chunk-YK5JEVLX.js";
|
|
@@ -10,6 +7,12 @@ import {
|
|
|
10
7
|
import {
|
|
11
8
|
PostgresCursorStore
|
|
12
9
|
} from "./chunk-XWBK3XJK.js";
|
|
10
|
+
import {
|
|
11
|
+
MemoryCursorStore
|
|
12
|
+
} from "./chunk-AHV4GDYM.js";
|
|
13
|
+
import {
|
|
14
|
+
DeepEqualDiffer
|
|
15
|
+
} from "./chunk-JEINYUJH.js";
|
|
13
16
|
import {
|
|
14
17
|
INTEGRATION_CURSOR_STORE,
|
|
15
18
|
INTEGRATION_FIELD_DIFFER,
|
|
@@ -17,9 +20,6 @@ import {
|
|
|
17
20
|
INTEGRATION_MULTI_TENANT,
|
|
18
21
|
INTEGRATION_RUN_RECORDER
|
|
19
22
|
} from "./chunk-S7C6TIIF.js";
|
|
20
|
-
import {
|
|
21
|
-
DeepEqualDiffer
|
|
22
|
-
} from "./chunk-JEINYUJH.js";
|
|
23
23
|
import {
|
|
24
24
|
__decorateClass
|
|
25
25
|
} from "./chunk-2E224ZSN.js";
|
|
@@ -84,4 +84,4 @@ IntegrationModule = __decorateClass([
|
|
|
84
84
|
export {
|
|
85
85
|
IntegrationModule
|
|
86
86
|
};
|
|
87
|
-
//# sourceMappingURL=chunk-
|
|
87
|
+
//# sourceMappingURL=chunk-ATVGYF3D.js.map
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DrizzleJobRunService
|
|
3
|
+
} from "./chunk-VNBC3VXM.js";
|
|
4
|
+
import {
|
|
5
|
+
MemoryJobRunService
|
|
6
|
+
} from "./chunk-BHZP6LOV.js";
|
|
1
7
|
import {
|
|
2
8
|
DrizzleJobStepService
|
|
3
9
|
} from "./chunk-DV4RV2DC.js";
|
|
4
10
|
import {
|
|
5
11
|
DrizzleJobOrchestrator
|
|
6
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-E6PLM6QG.js";
|
|
7
13
|
import {
|
|
8
14
|
MemoryJobOrchestrator
|
|
9
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-VQOAATIG.js";
|
|
10
16
|
import {
|
|
11
17
|
MemoryJobStepService
|
|
12
18
|
} from "./chunk-PNZSGAB2.js";
|
|
13
|
-
import {
|
|
14
|
-
DrizzleJobRunService
|
|
15
|
-
} from "./chunk-VNBC3VXM.js";
|
|
16
|
-
import {
|
|
17
|
-
MemoryJobRunService
|
|
18
|
-
} from "./chunk-BHZP6LOV.js";
|
|
19
19
|
import {
|
|
20
20
|
MemoryJobStore
|
|
21
21
|
} from "./chunk-SNQ3TOWP.js";
|
|
@@ -114,4 +114,4 @@ JobsDomainModule = __decorateClass([
|
|
|
114
114
|
export {
|
|
115
115
|
JobsDomainModule
|
|
116
116
|
};
|
|
117
|
-
//# sourceMappingURL=chunk-
|
|
117
|
+
//# sourceMappingURL=chunk-AZLUWG5S.js.map
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
clampEventLimit,
|
|
3
|
+
decodeEventCursor,
|
|
4
|
+
encodeEventCursor
|
|
5
|
+
} from "./chunk-UQ5EHOH2.js";
|
|
1
6
|
import {
|
|
2
7
|
EVENTS_WAKE_CHANNEL,
|
|
3
8
|
PgNotifyListener,
|
|
4
9
|
pgNotify
|
|
5
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-Q6LRJ4VI.js";
|
|
11
|
+
import {
|
|
12
|
+
EVENTS_MODULE_OPTIONS
|
|
13
|
+
} from "./chunk-H5NH7KPE.js";
|
|
6
14
|
import {
|
|
7
15
|
BRIDGE_OUTBOX_DRAIN_HOOK
|
|
8
16
|
} from "./chunk-4LH67P4U.js";
|
|
9
17
|
import {
|
|
10
18
|
domainEvents
|
|
11
19
|
} from "./chunk-OFRRBC7M.js";
|
|
12
|
-
import {
|
|
13
|
-
EVENTS_MODULE_OPTIONS
|
|
14
|
-
} from "./chunk-H5NH7KPE.js";
|
|
15
|
-
import {
|
|
16
|
-
clampEventLimit,
|
|
17
|
-
decodeEventCursor,
|
|
18
|
-
encodeEventCursor
|
|
19
|
-
} from "./chunk-UQ5EHOH2.js";
|
|
20
20
|
import {
|
|
21
21
|
DRIZZLE
|
|
22
22
|
} from "./chunk-U64T4YZE.js";
|
|
@@ -393,4 +393,4 @@ DrizzleEventBus = __decorateClass([
|
|
|
393
393
|
export {
|
|
394
394
|
DrizzleEventBus
|
|
395
395
|
};
|
|
396
|
-
//# sourceMappingURL=chunk-
|
|
396
|
+
//# sourceMappingURL=chunk-B34G6PHD.js.map
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
JOB_RUN_SERVICE
|
|
3
3
|
} from "./chunk-ZPL74UQN.js";
|
|
4
|
-
import {
|
|
5
|
-
BRIDGE_DELIVERY_REPO
|
|
6
|
-
} from "./chunk-4LH67P4U.js";
|
|
7
4
|
import {
|
|
8
5
|
EVENT_READ_PORT
|
|
9
6
|
} from "./chunk-H5NH7KPE.js";
|
|
7
|
+
import {
|
|
8
|
+
BRIDGE_DELIVERY_REPO
|
|
9
|
+
} from "./chunk-4LH67P4U.js";
|
|
10
10
|
import {
|
|
11
11
|
INTEGRATION_CURSOR_STORE,
|
|
12
12
|
INTEGRATION_RUN_RECORDER
|
|
@@ -181,4 +181,4 @@ ObservabilityService = __decorateClass([
|
|
|
181
181
|
export {
|
|
182
182
|
ObservabilityService
|
|
183
183
|
};
|
|
184
|
-
//# sourceMappingURL=chunk-
|
|
184
|
+
//# sourceMappingURL=chunk-CLWBNXKF.js.map
|
|
@@ -6,22 +6,22 @@ import {
|
|
|
6
6
|
MissingTenantIdError
|
|
7
7
|
} from "./chunk-T4BIIU5E.js";
|
|
8
8
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
} from "./chunk-
|
|
9
|
+
JOBS_WAKE_CHANNEL,
|
|
10
|
+
pgNotify
|
|
11
|
+
} from "./chunk-Q6LRJ4VI.js";
|
|
12
12
|
import {
|
|
13
13
|
keySelectorToTemplate,
|
|
14
14
|
resolveJobKey
|
|
15
15
|
} from "./chunk-7P5ODGLA.js";
|
|
16
|
+
import {
|
|
17
|
+
JOBS_LISTEN_NOTIFY,
|
|
18
|
+
JOBS_MULTI_TENANT
|
|
19
|
+
} from "./chunk-ZPL74UQN.js";
|
|
16
20
|
import {
|
|
17
21
|
jobRuns,
|
|
18
22
|
jobSteps,
|
|
19
23
|
jobs
|
|
20
24
|
} from "./chunk-OKXZ63IA.js";
|
|
21
|
-
import {
|
|
22
|
-
JOBS_WAKE_CHANNEL,
|
|
23
|
-
pgNotify
|
|
24
|
-
} from "./chunk-MYQIQ27N.js";
|
|
25
25
|
import {
|
|
26
26
|
DRIZZLE
|
|
27
27
|
} from "./chunk-U64T4YZE.js";
|
|
@@ -393,4 +393,4 @@ export {
|
|
|
393
393
|
evaluateKeyTemplate,
|
|
394
394
|
DrizzleJobOrchestrator
|
|
395
395
|
};
|
|
396
|
-
//# sourceMappingURL=chunk-
|
|
396
|
+
//# sourceMappingURL=chunk-E6PLM6QG.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
PollChangeSource
|
|
3
|
-
} from "./chunk-4MF3HKJA.js";
|
|
4
1
|
import {
|
|
5
2
|
WebhookChangeSource
|
|
6
3
|
} from "./chunk-TIZXQU26.js";
|
|
4
|
+
import {
|
|
5
|
+
PollChangeSource
|
|
6
|
+
} from "./chunk-4MF3HKJA.js";
|
|
7
7
|
|
|
8
8
|
// runtime/subsystems/integration/build-change-source.ts
|
|
9
9
|
function buildChangeSource(cfg, fetch, middlewares = []) {
|
|
@@ -26,4 +26,4 @@ function buildChangeSource(cfg, fetch, middlewares = []) {
|
|
|
26
26
|
export {
|
|
27
27
|
buildChangeSource
|
|
28
28
|
};
|
|
29
|
-
//# sourceMappingURL=chunk-
|
|
29
|
+
//# sourceMappingURL=chunk-I6UXRJ3Q.js.map
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-5A432NZJ.js";
|
|
4
4
|
import {
|
|
5
5
|
EventFlowService
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-7OVCARTQ.js";
|
|
7
7
|
import {
|
|
8
8
|
BRIDGE_RESERVED_POOLS
|
|
9
9
|
} from "./chunk-EDKJU5BO.js";
|
|
@@ -15,16 +15,16 @@ import {
|
|
|
15
15
|
} from "./chunk-4DOJBQTP.js";
|
|
16
16
|
import {
|
|
17
17
|
BridgeOutboxDrainHook
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-65MO75WM.js";
|
|
19
19
|
import {
|
|
20
20
|
BridgeDeliveryHandler
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-R6F6KFIL.js";
|
|
22
22
|
import {
|
|
23
23
|
BridgeReservedPoolsNotPolledError
|
|
24
24
|
} from "./chunk-NXXDZ6ZF.js";
|
|
25
25
|
import {
|
|
26
26
|
JOB_WORKER_MODULE_OPTIONS
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-235ZMMJR.js";
|
|
28
28
|
import {
|
|
29
29
|
BRIDGE_DELIVERY_REPO,
|
|
30
30
|
BRIDGE_MODULE_OPTIONS,
|
|
@@ -119,4 +119,4 @@ BridgeModule = __decorateClass([
|
|
|
119
119
|
export {
|
|
120
120
|
BridgeModule
|
|
121
121
|
};
|
|
122
|
-
//# sourceMappingURL=chunk-
|
|
122
|
+
//# sourceMappingURL=chunk-KZDHMZ45.js.map
|
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
} from "./chunk-GM3RMJIJ.js";
|
|
4
4
|
import {
|
|
5
5
|
DrizzleEventBus
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-B34G6PHD.js";
|
|
7
7
|
import {
|
|
8
8
|
MemoryEventBus
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-Z7PQCAVK.js";
|
|
10
10
|
import {
|
|
11
11
|
EVENTS_MODULE_OPTIONS,
|
|
12
12
|
EVENTS_MULTI_TENANT,
|
|
@@ -152,4 +152,4 @@ EventsModule = __decorateClass([
|
|
|
152
152
|
export {
|
|
153
153
|
EventsModule
|
|
154
154
|
};
|
|
155
|
-
//# sourceMappingURL=chunk-
|
|
155
|
+
//# sourceMappingURL=chunk-OZEPJGMA.js.map
|
|
@@ -27,24 +27,60 @@ var PgNotifyListener = class {
|
|
|
27
27
|
backoffMaxMs;
|
|
28
28
|
/** WARN-once gate so a flapping listener doesn't spam the log. */
|
|
29
29
|
warnedDown = false;
|
|
30
|
+
/**
|
|
31
|
+
* LISTEN-NOTIFY-2 — the in-flight `connect()` promise, set while a checkout is
|
|
32
|
+
* mid-`await`. `stop()` awaits it so a `stop()` that races a still-resolving
|
|
33
|
+
* `connect()` can't return before the connect either assigns `this.client`
|
|
34
|
+
* (then released by `releaseClient`) or self-releases the checked-out client.
|
|
35
|
+
* Without this, a `stop()` arriving during `pool.connect()`'s await saw
|
|
36
|
+
* `this.client === null` (nothing to release), then `connect()` resumed,
|
|
37
|
+
* assigned the client, and issued `LISTEN` — leaking an ESTABLISHED socket
|
|
38
|
+
* holding `LISTEN <channel>` forever past `app.close()`.
|
|
39
|
+
*/
|
|
40
|
+
connecting = null;
|
|
30
41
|
/** Begin listening. Idempotent-ish: a second call while connected is a no-op. */
|
|
31
42
|
async start() {
|
|
32
43
|
this.stopped = false;
|
|
33
44
|
await this.connect();
|
|
34
45
|
}
|
|
35
|
-
/**
|
|
46
|
+
/**
|
|
47
|
+
* Stop listening + release the connection. Safe to call repeatedly and
|
|
48
|
+
* race-safe against an in-flight `connect()` (LISTEN-NOTIFY-2): it sets
|
|
49
|
+
* `stopped` first (so a resuming `connect()` self-releases its checkout),
|
|
50
|
+
* then awaits any in-flight connect, then releases whatever client landed.
|
|
51
|
+
*/
|
|
36
52
|
async stop() {
|
|
37
53
|
this.stopped = true;
|
|
38
54
|
if (this.reconnectTimer) {
|
|
39
55
|
clearTimeout(this.reconnectTimer);
|
|
40
56
|
this.reconnectTimer = null;
|
|
41
57
|
}
|
|
58
|
+
const inflight = this.connecting;
|
|
59
|
+
if (inflight) {
|
|
60
|
+
try {
|
|
61
|
+
await inflight;
|
|
62
|
+
} catch {
|
|
63
|
+
}
|
|
64
|
+
}
|
|
42
65
|
await this.releaseClient();
|
|
43
66
|
}
|
|
44
67
|
async connect() {
|
|
45
68
|
if (this.stopped) return;
|
|
69
|
+
const attempt = this.doConnect();
|
|
70
|
+
this.connecting = attempt;
|
|
71
|
+
try {
|
|
72
|
+
await attempt;
|
|
73
|
+
} finally {
|
|
74
|
+
if (this.connecting === attempt) this.connecting = null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
async doConnect() {
|
|
46
78
|
try {
|
|
47
79
|
const client = await this.opts.pool.connect();
|
|
80
|
+
if (this.stopped) {
|
|
81
|
+
await this.releaseRawClient(client);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
48
84
|
client.on("notification", (msg) => {
|
|
49
85
|
if (msg.channel !== this.opts.channel) return;
|
|
50
86
|
try {
|
|
@@ -58,6 +94,10 @@ var PgNotifyListener = class {
|
|
|
58
94
|
this.handleDrop();
|
|
59
95
|
});
|
|
60
96
|
await client.query(`LISTEN ${this.opts.channel}`);
|
|
97
|
+
if (this.stopped) {
|
|
98
|
+
await this.releaseRawClient(client);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
61
101
|
this.client = client;
|
|
62
102
|
if (this.warnedDown) {
|
|
63
103
|
this.logger.log(
|
|
@@ -99,6 +139,15 @@ var PgNotifyListener = class {
|
|
|
99
139
|
const client = this.client;
|
|
100
140
|
this.client = null;
|
|
101
141
|
if (!client) return;
|
|
142
|
+
await this.releaseRawClient(client);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Tear down a raw checked-out client (LISTEN-NOTIFY-2). Used both by the
|
|
146
|
+
* normal `releaseClient()` path and by the connect-vs-stop race bail-outs,
|
|
147
|
+
* where the client was checked out but never assigned to `this.client`.
|
|
148
|
+
* Destroys (`release(true)`) so a half-listening socket is never reused.
|
|
149
|
+
*/
|
|
150
|
+
async releaseRawClient(client) {
|
|
102
151
|
try {
|
|
103
152
|
client.removeAllListeners?.("notification");
|
|
104
153
|
client.removeAllListeners?.("error");
|
|
@@ -115,4 +164,4 @@ export {
|
|
|
115
164
|
pgNotify,
|
|
116
165
|
PgNotifyListener
|
|
117
166
|
};
|
|
118
|
-
//# sourceMappingURL=chunk-
|
|
167
|
+
//# sourceMappingURL=chunk-Q6LRJ4VI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../runtime/subsystems/jobs/pg-notify.ts"],"sourcesContent":["/**\n * PgNotifyListener + pgNotify — Postgres LISTEN/NOTIFY wakeups\n * (LISTEN-NOTIFY-1, dogfood gap #7).\n *\n * The drizzle jobs worker and events outbox drainer poll on an interval today\n * (default 1 s/hop). With `listen_notify` enabled, a row write that makes work\n * claimable emits an in-transaction `pg_notify(...)`; a dedicated listener\n * connection wakes the polling loop the moment the writing transaction commits.\n *\n * Two halves:\n * - `pgNotify(tx, channel, payload)` — fire an in-tx `pg_notify`. MUST be\n * called with the SAME transaction handle as the row write it announces, so\n * Postgres delivers it only on commit (the transactional-outbox guarantee).\n * - `PgNotifyListener` — owns a single long-lived `pg.PoolClient`, issues\n * `LISTEN <channel>`, forwards each notification's payload to an owner\n * callback, debounces bursts, and reconnects with capped backoff on drop.\n *\n * **Polling never stops.** This is a wake-early optimisation layered ON TOP of\n * interval polling. A lost notification (listener down, pooler eats the LISTEN,\n * etc.) degrades to today's poll latency, never to lost work — the claim/drain\n * query remains the source of truth.\n *\n * **PgBouncer caveat:** session-scoped `LISTEN` does not survive a\n * transaction-mode pooler. `listen_notify` requires a direct (or session-mode)\n * connection; behind a transaction pooler notifies are simply never received and\n * the system degrades to polling. See the jobs config block / skill.\n */\n// TODO(logging-subsystem): swap to ILogger once ADR-028 lands\nimport { Logger } from '@nestjs/common';\nimport { sql } from 'drizzle-orm';\nimport type { DrizzleClient } from '../../types/drizzle';\nimport type { DrizzleTransaction } from '../events/event-bus.protocol';\n\n/** Channel the jobs worker LISTENs on; payload = pool name. */\nexport const JOBS_WAKE_CHANNEL = 'codegen_jobs_wake';\n/** Channel the events drainer LISTENs on; payload = event pool (or ''). */\nexport const EVENTS_WAKE_CHANNEL = 'codegen_events_wake';\n\n/**\n * Emit an in-transaction `pg_notify`. Call with the SAME `tx`/client handle as\n * the row write being announced so delivery is gated on commit. `payload` is a\n * short plain string (a pool name); it is NOT JSON — the wake is a hint and the\n * subsequent claim/drain query is authoritative. Channel names are framework\n * constants (never user input), so the `set_config`-free literal-channel form is\n * safe; the payload is bound as a parameter.\n */\nexport async function pgNotify(\n tx: DrizzleClient | DrizzleTransaction,\n channel: string,\n payload: string,\n): Promise<void> {\n const client = tx as DrizzleClient;\n // `pg_notify(channel, payload)` is the function form (vs the `NOTIFY chan,\n // 'payload'` statement form) precisely because it accepts bound parameters —\n // the payload is parameterised, never string-concatenated.\n await client.execute(sql`select pg_notify(${channel}, ${payload})`);\n}\n\n/** Minimal structural view of the `pg` Client/PoolClient surface we touch. */\ninterface PgListenClient {\n query(text: string): Promise<unknown>;\n on(event: 'notification', cb: (msg: { channel: string; payload?: string }) => void): void;\n on(event: 'error', cb: (err: Error) => void): void;\n removeAllListeners?: (event?: string) => void;\n release?: (err?: boolean) => void;\n end?: () => Promise<void>;\n}\n\n/** Minimal structural view of the `pg` Pool's `connect()`. */\ninterface PgPoolish {\n connect(): Promise<PgListenClient>;\n}\n\nconst DEFAULT_BACKOFF_MIN_MS = 100;\nconst DEFAULT_BACKOFF_MAX_MS = 5_000;\n\nexport interface PgNotifyListenerOptions {\n /** Channel to LISTEN on. */\n channel: string;\n /**\n * The underlying `pg.Pool` — obtained from `drizzleClient.$client`. A\n * dedicated `PoolClient` is checked out and held for the listener's lifetime\n * (separate from the query pool so a slow query never delays a wake).\n */\n pool: PgPoolish;\n /**\n * Called for every notification on `channel`, with the raw payload string\n * (`''` when Postgres delivers an empty payload). The owner decides whether\n * the payload is relevant (e.g. \"is this one of my pools?\") and debounces its\n * own claim cycle.\n */\n onNotify: (payload: string) => void;\n /** Label used in log lines (e.g. 'jobs:interactive', 'events'). */\n label: string;\n backoffMinMs?: number;\n backoffMaxMs?: number;\n}\n\n/**\n * Holds a dedicated listener connection and forwards notifications to `onNotify`.\n * Reconnects with capped exponential backoff on drop; logs the first failure +\n * the recovery exactly once each so a flapping connection doesn't flood logs.\n */\nexport class PgNotifyListener {\n private readonly logger: Logger;\n private client: PgListenClient | null = null;\n private stopped = false;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private backoffMs: number;\n private readonly backoffMinMs: number;\n private readonly backoffMaxMs: number;\n /** WARN-once gate so a flapping listener doesn't spam the log. */\n private warnedDown = false;\n /**\n * LISTEN-NOTIFY-2 — the in-flight `connect()` promise, set while a checkout is\n * mid-`await`. `stop()` awaits it so a `stop()` that races a still-resolving\n * `connect()` can't return before the connect either assigns `this.client`\n * (then released by `releaseClient`) or self-releases the checked-out client.\n * Without this, a `stop()` arriving during `pool.connect()`'s await saw\n * `this.client === null` (nothing to release), then `connect()` resumed,\n * assigned the client, and issued `LISTEN` — leaking an ESTABLISHED socket\n * holding `LISTEN <channel>` forever past `app.close()`.\n */\n private connecting: Promise<void> | null = null;\n\n constructor(private readonly opts: PgNotifyListenerOptions) {\n this.logger = new Logger(`PgNotifyListener(${opts.label})`);\n this.backoffMinMs = opts.backoffMinMs ?? DEFAULT_BACKOFF_MIN_MS;\n this.backoffMaxMs = opts.backoffMaxMs ?? DEFAULT_BACKOFF_MAX_MS;\n this.backoffMs = this.backoffMinMs;\n }\n\n /** Begin listening. Idempotent-ish: a second call while connected is a no-op. */\n async start(): Promise<void> {\n this.stopped = false;\n await this.connect();\n }\n\n /**\n * Stop listening + release the connection. Safe to call repeatedly and\n * race-safe against an in-flight `connect()` (LISTEN-NOTIFY-2): it sets\n * `stopped` first (so a resuming `connect()` self-releases its checkout),\n * then awaits any in-flight connect, then releases whatever client landed.\n */\n async stop(): Promise<void> {\n this.stopped = true;\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n // Await an in-flight checkout so we don't return while a client is still\n // mid-`pool.connect()`. The resuming `connect()` sees `stopped` and either\n // self-releases its checkout or assigns `this.client`; either way the\n // `releaseClient()` below mops up.\n const inflight = this.connecting;\n if (inflight) {\n try {\n await inflight;\n } catch {\n // connect failures are handled inside connect(); ignore here.\n }\n }\n await this.releaseClient();\n }\n\n private async connect(): Promise<void> {\n if (this.stopped) return;\n // Track this checkout so a racing stop() can await it (LISTEN-NOTIFY-2).\n const attempt = this.doConnect();\n this.connecting = attempt;\n try {\n await attempt;\n } finally {\n if (this.connecting === attempt) this.connecting = null;\n }\n }\n\n private async doConnect(): Promise<void> {\n try {\n const client = await this.opts.pool.connect();\n // Re-check AFTER the await resolves: a stop() may have fired while this\n // checkout was in flight. If so, release the just-checked-out client\n // right here and bail BEFORE wiring handlers / issuing LISTEN — otherwise\n // we'd leak an ESTABLISHED listener socket past shutdown (LISTEN-NOTIFY-2).\n if (this.stopped) {\n await this.releaseRawClient(client);\n return;\n }\n client.on('notification', (msg) => {\n if (msg.channel !== this.opts.channel) return;\n try {\n this.opts.onNotify(msg.payload ?? '');\n } catch (err) {\n this.logger.error(`onNotify threw: ${(err as Error).message}`);\n }\n });\n client.on('error', (err) => {\n // A connection-level error is the signal to reconnect. Don't double-log\n // here — scheduleReconnect owns the WARN-once.\n this.logger.debug?.(`listener connection error: ${err.message}`);\n this.handleDrop();\n });\n await client.query(`LISTEN ${this.opts.channel}`);\n // A stop() could have fired during the LISTEN round-trip too — same guard.\n if (this.stopped) {\n await this.releaseRawClient(client);\n return;\n }\n this.client = client;\n // Recovery: only announce if we had previously warned about being down.\n if (this.warnedDown) {\n this.logger.log(\n `listener reconnected; LISTEN ${this.opts.channel} re-established`,\n );\n this.warnedDown = false;\n }\n this.backoffMs = this.backoffMinMs;\n } catch (err) {\n this.handleConnectFailure(err);\n }\n }\n\n /** Connection dropped after being established → reconnect. */\n private handleDrop(): void {\n if (this.stopped) return;\n void this.releaseClient().finally(() => this.scheduleReconnect());\n }\n\n /** Initial / reconnect `connect()` threw. */\n private handleConnectFailure(err: unknown): void {\n this.scheduleReconnect(err);\n }\n\n private scheduleReconnect(err?: unknown): void {\n if (this.stopped) return;\n if (!this.warnedDown) {\n this.warnedDown = true;\n this.logger.warn(\n `listener down — falling back to interval polling until reconnect. ` +\n `Cause: ${err instanceof Error ? err.message : 'connection lost'}. ` +\n `(This degrades latency, not durability — polling still drives all work.)`,\n );\n }\n if (this.reconnectTimer) clearTimeout(this.reconnectTimer);\n const delay = this.backoffMs;\n this.backoffMs = Math.min(this.backoffMs * 2, this.backoffMaxMs);\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n void this.connect();\n }, delay);\n }\n\n private async releaseClient(): Promise<void> {\n const client = this.client;\n this.client = null;\n if (!client) return;\n await this.releaseRawClient(client);\n }\n\n /**\n * Tear down a raw checked-out client (LISTEN-NOTIFY-2). Used both by the\n * normal `releaseClient()` path and by the connect-vs-stop race bail-outs,\n * where the client was checked out but never assigned to `this.client`.\n * Destroys (`release(true)`) so a half-listening socket is never reused.\n */\n private async releaseRawClient(client: PgListenClient): Promise<void> {\n try {\n client.removeAllListeners?.('notification');\n client.removeAllListeners?.('error');\n if (client.release) client.release(true);\n else if (client.end) await client.end();\n } catch {\n // best-effort teardown\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
2
|
assertTenantId
|
|
3
3
|
} from "./chunk-6DWFJNIK.js";
|
|
4
|
-
import {
|
|
5
|
-
JOB_ORCHESTRATOR
|
|
6
|
-
} from "./chunk-ZPL74UQN.js";
|
|
7
4
|
import {
|
|
8
5
|
JobHandler,
|
|
9
6
|
JobHandlerBase
|
|
10
7
|
} from "./chunk-7P5ODGLA.js";
|
|
8
|
+
import {
|
|
9
|
+
JOB_ORCHESTRATOR
|
|
10
|
+
} from "./chunk-ZPL74UQN.js";
|
|
11
|
+
import {
|
|
12
|
+
EVENT_BUS
|
|
13
|
+
} from "./chunk-H5NH7KPE.js";
|
|
11
14
|
import {
|
|
12
15
|
BRIDGE_DELIVERY_REPO,
|
|
13
16
|
BRIDGE_MULTI_TENANT,
|
|
14
17
|
BRIDGE_REGISTRY
|
|
15
18
|
} from "./chunk-4LH67P4U.js";
|
|
16
|
-
import {
|
|
17
|
-
EVENT_BUS
|
|
18
|
-
} from "./chunk-H5NH7KPE.js";
|
|
19
19
|
import {
|
|
20
20
|
__decorateClass,
|
|
21
21
|
__decorateParam
|
|
@@ -118,4 +118,4 @@ export {
|
|
|
118
118
|
BRIDGE_DELIVERY_JOB_TYPE,
|
|
119
119
|
BridgeDeliveryHandler
|
|
120
120
|
};
|
|
121
|
-
//# sourceMappingURL=chunk-
|
|
121
|
+
//# sourceMappingURL=chunk-R6F6KFIL.js.map
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
JOBS_WAKE_CHANNEL,
|
|
3
|
+
PgNotifyListener
|
|
4
|
+
} from "./chunk-Q6LRJ4VI.js";
|
|
5
|
+
import {
|
|
6
|
+
JOB_HANDLER_REGISTRY
|
|
7
|
+
} from "./chunk-7P5ODGLA.js";
|
|
1
8
|
import {
|
|
2
9
|
JOB_ORCHESTRATOR,
|
|
3
10
|
JOB_RUN_SERVICE,
|
|
4
11
|
JOB_STEP_SERVICE
|
|
5
12
|
} from "./chunk-ZPL74UQN.js";
|
|
6
|
-
import {
|
|
7
|
-
JOB_HANDLER_REGISTRY
|
|
8
|
-
} from "./chunk-7P5ODGLA.js";
|
|
9
13
|
import {
|
|
10
14
|
jobRuns
|
|
11
15
|
} from "./chunk-OKXZ63IA.js";
|
|
12
|
-
import {
|
|
13
|
-
JOBS_WAKE_CHANNEL,
|
|
14
|
-
PgNotifyListener
|
|
15
|
-
} from "./chunk-MYQIQ27N.js";
|
|
16
16
|
import {
|
|
17
17
|
tokenKey
|
|
18
18
|
} from "./chunk-GYGNEQSC.js";
|
|
@@ -199,6 +199,7 @@ var JobWorker = class {
|
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
201
|
async onModuleDestroy() {
|
|
202
|
+
await this.stopNotifyListener();
|
|
202
203
|
if (this.shuttingDown) {
|
|
203
204
|
await this.drainInFlight();
|
|
204
205
|
return;
|
|
@@ -213,14 +214,6 @@ var JobWorker = class {
|
|
|
213
214
|
this.sweeperTimer = null;
|
|
214
215
|
}
|
|
215
216
|
process.removeListener("SIGTERM", this.sigtermHandler);
|
|
216
|
-
if (this.notifyListener) {
|
|
217
|
-
try {
|
|
218
|
-
await this.notifyListener.stop();
|
|
219
|
-
} catch (err) {
|
|
220
|
-
this.logger.error(`notify listener stop failed: ${err.message}`);
|
|
221
|
-
}
|
|
222
|
-
this.notifyListener = null;
|
|
223
|
-
}
|
|
224
217
|
await this.drainInFlight();
|
|
225
218
|
try {
|
|
226
219
|
await this.db.update(jobRuns).set({ status: "pending", claimedAt: null, startedAt: null }).where(
|
|
@@ -240,6 +233,23 @@ var JobWorker = class {
|
|
|
240
233
|
timeout
|
|
241
234
|
]);
|
|
242
235
|
}
|
|
236
|
+
/**
|
|
237
|
+
* LISTEN-NOTIFY-2 — stop + drop the wake listener. Idempotent: a second call
|
|
238
|
+
* (SIGTERM + Nest destroy) finds `notifyListener` already null and no-ops.
|
|
239
|
+
* `PgNotifyListener.stop()` is itself race-safe against an in-flight
|
|
240
|
+
* `connect()`, so even a destroy that arrives microseconds after `start()`
|
|
241
|
+
* releases the listener socket rather than leaking it.
|
|
242
|
+
*/
|
|
243
|
+
async stopNotifyListener() {
|
|
244
|
+
const listener = this.notifyListener;
|
|
245
|
+
if (!listener) return;
|
|
246
|
+
this.notifyListener = null;
|
|
247
|
+
try {
|
|
248
|
+
await listener.stop();
|
|
249
|
+
} catch (err) {
|
|
250
|
+
this.logger.error(`notify listener stop failed: ${err.message}`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
243
253
|
// ============================================================================
|
|
244
254
|
// Poll loop
|
|
245
255
|
// ============================================================================
|
|
@@ -518,4 +528,4 @@ export {
|
|
|
518
528
|
buildStaleSweepQuery,
|
|
519
529
|
JobWorker
|
|
520
530
|
};
|
|
521
|
-
//# sourceMappingURL=chunk-
|
|
531
|
+
//# sourceMappingURL=chunk-VDL5CJ5C.js.map
|