@nestjs-transactional/outbox 1.0.0-alpha.5 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +174 -335
  2. package/dist/api/failed-event-publications.js.map +1 -1
  3. package/dist/api/incomplete-event-publications.js +1 -2
  4. package/dist/api/incomplete-event-publications.js.map +1 -1
  5. package/dist/decorators/outbox-events-handler.decorator.d.ts +1 -1
  6. package/dist/decorators/outbox-events-handler.decorator.js.map +1 -1
  7. package/dist/dispatcher/data-source-outbox-publisher.d.ts +2 -3
  8. package/dist/dispatcher/data-source-outbox-publisher.js +2 -3
  9. package/dist/dispatcher/data-source-outbox-publisher.js.map +1 -1
  10. package/dist/dispatcher/event-publication-processor.d.ts +19 -2
  11. package/dist/dispatcher/event-publication-processor.js +40 -3
  12. package/dist/dispatcher/event-publication-processor.js.map +1 -1
  13. package/dist/dispatcher/outbox-event-publisher.d.ts +1 -1
  14. package/dist/dispatcher/outbox-event-publisher.js +2 -2
  15. package/dist/dispatcher/outbox-event-publisher.js.map +1 -1
  16. package/dist/dispatcher/processor-options.d.ts +13 -1
  17. package/dist/dispatcher/processor-options.js +4 -1
  18. package/dist/dispatcher/processor-options.js.map +1 -1
  19. package/dist/externalization/describe-thrown.d.ts +20 -0
  20. package/dist/externalization/describe-thrown.js +49 -0
  21. package/dist/externalization/describe-thrown.js.map +1 -0
  22. package/dist/externalization/event-externalizer.d.ts +2 -2
  23. package/dist/externalization/externalization-registry.js.map +1 -1
  24. package/dist/externalization/externalized.decorator.d.ts +3 -4
  25. package/dist/externalization/externalized.decorator.js +2 -3
  26. package/dist/externalization/externalized.decorator.js.map +1 -1
  27. package/dist/externalization/types.d.ts +2 -2
  28. package/dist/index.d.ts +6 -0
  29. package/dist/index.js +11 -1
  30. package/dist/index.js.map +1 -1
  31. package/dist/module/outbox-processing.module.d.ts +18 -2
  32. package/dist/module/outbox-processing.module.js +33 -7
  33. package/dist/module/outbox-processing.module.js.map +1 -1
  34. package/dist/module/outbox.module.d.ts +15 -0
  35. package/dist/module/outbox.module.js +99 -8
  36. package/dist/module/outbox.module.js.map +1 -1
  37. package/dist/recovery/outbox-cleanup-scheduler.d.ts +56 -0
  38. package/dist/recovery/outbox-cleanup-scheduler.js +139 -0
  39. package/dist/recovery/outbox-cleanup-scheduler.js.map +1 -0
  40. package/dist/recovery/outbox-retry-scheduler.d.ts +68 -0
  41. package/dist/recovery/outbox-retry-scheduler.js +163 -0
  42. package/dist/recovery/outbox-retry-scheduler.js.map +1 -0
  43. package/dist/recovery/staleness-monitor.d.ts +10 -2
  44. package/dist/recovery/staleness-monitor.js +28 -3
  45. package/dist/recovery/staleness-monitor.js.map +1 -1
  46. package/dist/registry/event-publication-registry.d.ts +1 -1
  47. package/dist/registry/event-publication-registry.js +1 -1
  48. package/dist/registry/event-publication-registry.js.map +1 -1
  49. package/dist/registry/listener-registry.d.ts +2 -2
  50. package/dist/registry/listener-registry.js +2 -2
  51. package/dist/registry/multi-ds-listener-registrar.d.ts +10 -4
  52. package/dist/registry/multi-ds-listener-registrar.js +1 -1
  53. package/dist/registry/multi-ds-listener-registrar.js.map +1 -1
  54. package/dist/registry/outbox-listener-scanner.d.ts +1 -1
  55. package/dist/registry/outbox-listener-scanner.js +1 -1
  56. package/dist/registry/outbox-listener-scanner.js.map +1 -1
  57. package/dist/repository/event-publication-repository.d.ts +37 -6
  58. package/dist/repository/event-publication-repository.js.map +1 -1
  59. package/dist/serialization/event-type-resolver.d.ts +1 -1
  60. package/dist/serialization/event-type-resolver.js +1 -1
  61. package/dist/serialization/json-event-serializer.js.map +1 -1
  62. package/dist/shutdown/drain.d.ts +32 -0
  63. package/dist/shutdown/drain.js +56 -0
  64. package/dist/shutdown/drain.js.map +1 -0
  65. package/dist/testing/in-memory-repository.js +11 -2
  66. package/dist/testing/in-memory-repository.js.map +1 -1
  67. package/dist/testing/published-events.js +6 -2
  68. package/dist/testing/published-events.js.map +1 -1
  69. package/dist/tokens/token-utils.js.map +1 -1
  70. package/dist/types/cleanup-config.d.ts +59 -0
  71. package/dist/types/cleanup-config.js +17 -0
  72. package/dist/types/cleanup-config.js.map +1 -0
  73. package/dist/types/resubmission-options.d.ts +0 -4
  74. package/dist/types/resubmission-options.js +0 -9
  75. package/dist/types/resubmission-options.js.map +1 -1
  76. package/dist/types/retry-config.d.ts +51 -0
  77. package/dist/types/retry-config.js +16 -0
  78. package/dist/types/retry-config.js.map +1 -0
  79. package/dist/types/staleness-config.d.ts +8 -0
  80. package/dist/types/staleness-config.js +2 -0
  81. package/dist/types/staleness-config.js.map +1 -1
  82. package/package.json +25 -13
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var OutboxRetryScheduler_1;
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.OutboxRetryScheduler = void 0;
14
+ const common_1 = require("@nestjs/common");
15
+ const failed_event_publications_1 = require("../api/failed-event-publications");
16
+ const drain_1 = require("../shutdown/drain");
17
+ const resubmission_options_1 = require("../types/resubmission-options");
18
+ /**
19
+ * Periodically resubmits `FAILED` publications whose backoff window has
20
+ * elapsed, up to a per-publication attempt cap (DD-026).
21
+ *
22
+ * Deliberately a thin scheduler over
23
+ * {@link FailedEventPublications.resubmit} rather than a second
24
+ * resubmission path: automatic retry is the same operation an operator
25
+ * performs by hand, on a timer, with a backoff predicate as the filter.
26
+ * Spring Modulith stops at the manual API — this is where we go one step
27
+ * past parity, and keeping it layered is what makes that step cheap to
28
+ * reason about.
29
+ *
30
+ * Disabled unless `config.maxAttempts > 0`, in which case {@link start}
31
+ * never schedules the loop. A publication that exhausts its attempts is
32
+ * simply no longer selected; it stays `FAILED` and remains available to
33
+ * the operator APIs.
34
+ */
35
+ let OutboxRetryScheduler = OutboxRetryScheduler_1 = class OutboxRetryScheduler {
36
+ failed;
37
+ config;
38
+ logger = new common_1.Logger(OutboxRetryScheduler_1.name);
39
+ running = false;
40
+ retryLoop = null;
41
+ /** The pass currently running, or `null` when idle. See {@link stop}. */
42
+ inFlightPass = null;
43
+ constructor(failed, config) {
44
+ this.failed = failed;
45
+ this.config = config;
46
+ }
47
+ /** Start the retry loop. Idempotent; a no-op when retry is disabled. */
48
+ start() {
49
+ if (this.running) {
50
+ return;
51
+ }
52
+ if (this.config.maxAttempts <= 0) {
53
+ this.logger.log('OutboxRetryScheduler disabled (maxAttempts = 0)');
54
+ return;
55
+ }
56
+ this.running = true;
57
+ this.scheduleNext();
58
+ this.logger.log(`OutboxRetryScheduler started (interval: ${this.config.interval}ms, ` +
59
+ `maxAttempts: ${this.config.maxAttempts})`);
60
+ }
61
+ /**
62
+ * Stop the loop and drain the pass already in flight, bounded by
63
+ * `config.shutdownTimeout`. Idempotent; never rejects.
64
+ */
65
+ async stop() {
66
+ this.running = false;
67
+ if (this.retryLoop !== null) {
68
+ clearTimeout(this.retryLoop);
69
+ this.retryLoop = null;
70
+ }
71
+ const inFlight = this.inFlightPass;
72
+ if (inFlight !== null) {
73
+ const drained = await (0, drain_1.drainWithTimeout)(inFlight, this.config.shutdownTimeout);
74
+ if (!drained) {
75
+ this.logger.warn(`OutboxRetryScheduler drain timed out after ${this.config.shutdownTimeout}ms — ` +
76
+ 'the in-flight pass was abandoned.');
77
+ }
78
+ }
79
+ }
80
+ /**
81
+ * Run a single retry pass and return how many publications were
82
+ * resubmitted. Invoked by the scheduled loop, and directly by tests
83
+ * and one-shot tooling.
84
+ *
85
+ * Never rejects: a failing pass is logged and reported as `0`, so a
86
+ * database blip cannot kill the loop.
87
+ */
88
+ async runOnce() {
89
+ try {
90
+ const resubmitted = await this.failed.resubmit(resubmission_options_1.ResubmissionOptions.defaults()
91
+ .withBatchSize(this.config.batchSize)
92
+ // The repository narrows by attempt count; `maxAttempts` counts
93
+ // the first delivery, so a publication is eligible only while
94
+ // it has attempts left.
95
+ .withMaxAttempts(this.config.maxAttempts - 1)
96
+ .withFilter((publication) => this.isDue(publication)));
97
+ if (resubmitted > 0) {
98
+ this.logger.log(`Resubmitted ${resubmitted} failed publication(s) for retry`);
99
+ }
100
+ return resubmitted;
101
+ }
102
+ catch (err) {
103
+ this.logger.error('Retry pass failed', err instanceof Error ? err.stack : String(err));
104
+ return 0;
105
+ }
106
+ }
107
+ /**
108
+ * Whether `publication` has waited out its backoff window.
109
+ *
110
+ * The window is measured from the last attempt we can see. There is no
111
+ * failure timestamp in the schema, so a publication that has never
112
+ * been resubmitted is measured from `publicationDate` — which makes
113
+ * its *first* retry eager if it lived a long time before failing.
114
+ * Every later window is exact, because resubmission stamps
115
+ * `lastResubmissionDate`. See DD-026 for why that beats a migration.
116
+ */
117
+ isDue(publication) {
118
+ const lastAttemptAt = publication.lastResubmissionDate ?? publication.publicationDate;
119
+ const waited = Date.now() - lastAttemptAt.getTime();
120
+ return waited >= this.delayFor(publication.completionAttempts);
121
+ }
122
+ /**
123
+ * `baseDelay * factor^(attempts - 1)`, clamped to `maxDelay` and then
124
+ * spread by `jitter`.
125
+ *
126
+ * Jitter scales the window by a factor in `[1 - jitter, 1 + jitter]`,
127
+ * so retries after a mass failure do not all become due at the same
128
+ * instant. It can shorten a window but never to zero, so a
129
+ * just-failed publication still waits.
130
+ */
131
+ delayFor(attempts) {
132
+ const exponent = Math.max(0, attempts - 1);
133
+ const raw = this.config.baseDelay * Math.pow(this.config.factor, exponent);
134
+ const clamped = Math.min(raw, this.config.maxDelay);
135
+ if (this.config.jitter <= 0) {
136
+ return clamped;
137
+ }
138
+ const spread = clamped * this.config.jitter;
139
+ return clamped - spread + Math.random() * spread * 2;
140
+ }
141
+ scheduleNext() {
142
+ if (!this.running) {
143
+ return;
144
+ }
145
+ this.retryLoop = setTimeout(() => {
146
+ this.retryLoop = null;
147
+ const pass = this.runOnce();
148
+ this.inFlightPass = pass;
149
+ void pass.finally(() => {
150
+ if (this.inFlightPass === pass) {
151
+ this.inFlightPass = null;
152
+ }
153
+ this.scheduleNext();
154
+ });
155
+ }, this.config.interval);
156
+ }
157
+ };
158
+ exports.OutboxRetryScheduler = OutboxRetryScheduler;
159
+ exports.OutboxRetryScheduler = OutboxRetryScheduler = OutboxRetryScheduler_1 = __decorate([
160
+ (0, common_1.Injectable)(),
161
+ __metadata("design:paramtypes", [failed_event_publications_1.FailedEventPublications, Object])
162
+ ], OutboxRetryScheduler);
163
+ //# sourceMappingURL=outbox-retry-scheduler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outbox-retry-scheduler.js","sourceRoot":"","sources":["../../src/recovery/outbox-retry-scheduler.ts"],"names":[],"mappings":"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"}
@@ -22,11 +22,19 @@ export declare class StalenessMonitor {
22
22
  private readonly logger;
23
23
  private running;
24
24
  private monitorLoop;
25
+ /** The sweep currently running, or `null` when idle. See {@link stop}. */
26
+ private inFlightSweep;
25
27
  constructor(repository: EventPublicationRepository, config: StalenessConfig);
26
28
  /** Start the watchdog. Idempotent. */
27
29
  start(): void;
28
- /** Stop the watchdog and cancel any pending scheduled tick. */
29
- stop(): void;
30
+ /**
31
+ * Stop the watchdog and drain the sweep already in flight.
32
+ *
33
+ * Resolves once no sweep is running, or once
34
+ * `config.shutdownTimeout` elapses — whichever comes first. Idempotent
35
+ * and never rejects.
36
+ */
37
+ stop(): Promise<void>;
30
38
  /**
31
39
  * Run a single staleness sweep — invoked both by the scheduled loop
32
40
  * and directly by tests / one-shot tooling. Never rejects; infra
@@ -16,6 +16,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
16
16
  exports.StalenessMonitor = void 0;
17
17
  const common_1 = require("@nestjs/common");
18
18
  const event_publication_repository_1 = require("../repository/event-publication-repository");
19
+ const drain_1 = require("../shutdown/drain");
19
20
  const publication_status_1 = require("../types/publication-status");
20
21
  /**
21
22
  * Periodic watchdog that flips publications stuck in non-terminal
@@ -39,6 +40,8 @@ let StalenessMonitor = StalenessMonitor_1 = class StalenessMonitor {
39
40
  logger = new common_1.Logger(StalenessMonitor_1.name);
40
41
  running = false;
41
42
  monitorLoop = null;
43
+ /** The sweep currently running, or `null` when idle. See {@link stop}. */
44
+ inFlightSweep = null;
42
45
  constructor(repository, config) {
43
46
  this.repository = repository;
44
47
  this.config = config;
@@ -58,13 +61,27 @@ let StalenessMonitor = StalenessMonitor_1 = class StalenessMonitor {
58
61
  this.scheduleNext();
59
62
  this.logger.log(`StalenessMonitor started (interval: ${this.config.monitorInterval}ms)`);
60
63
  }
61
- /** Stop the watchdog and cancel any pending scheduled tick. */
62
- stop() {
64
+ /**
65
+ * Stop the watchdog and drain the sweep already in flight.
66
+ *
67
+ * Resolves once no sweep is running, or once
68
+ * `config.shutdownTimeout` elapses — whichever comes first. Idempotent
69
+ * and never rejects.
70
+ */
71
+ async stop() {
63
72
  this.running = false;
64
73
  if (this.monitorLoop !== null) {
65
74
  clearTimeout(this.monitorLoop);
66
75
  this.monitorLoop = null;
67
76
  }
77
+ const inFlight = this.inFlightSweep;
78
+ if (inFlight !== null) {
79
+ const drained = await (0, drain_1.drainWithTimeout)(inFlight, this.config.shutdownTimeout);
80
+ if (!drained) {
81
+ this.logger.warn(`StalenessMonitor drain timed out after ${this.config.shutdownTimeout}ms — ` +
82
+ 'the in-flight sweep was abandoned.');
83
+ }
84
+ }
68
85
  }
69
86
  /**
70
87
  * Run a single staleness sweep — invoked both by the scheduled loop
@@ -93,7 +110,15 @@ let StalenessMonitor = StalenessMonitor_1 = class StalenessMonitor {
93
110
  return;
94
111
  }
95
112
  this.monitorLoop = setTimeout(() => {
96
- void this.checkStaleness().finally(() => this.scheduleNext());
113
+ this.monitorLoop = null;
114
+ const sweep = this.checkStaleness();
115
+ this.inFlightSweep = sweep;
116
+ void sweep.finally(() => {
117
+ if (this.inFlightSweep === sweep) {
118
+ this.inFlightSweep = null;
119
+ }
120
+ this.scheduleNext();
121
+ });
97
122
  }, this.config.monitorInterval);
98
123
  }
99
124
  async markStale(beforeDate, statuses, reason) {
@@ -1 +1 @@
1
- {"version":3,"file":"staleness-monitor.js","sourceRoot":"","sources":["../../src/recovery/staleness-monitor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"staleness-monitor.js","sourceRoot":"","sources":["../../src/recovery/staleness-monitor.ts"],"names":[],"mappings":"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"}
@@ -12,7 +12,7 @@ import type { EventPublication } from '../types/event-publication';
12
12
  * `COMPLETED` / `FAILED` → `RESUBMITTED`);
13
13
  * - hand out deserialized event payloads ready for listener invocation.
14
14
  *
15
- * Does NOT invoke listeners — that is the dispatcher's job (Phase 5.6).
15
+ * Does NOT invoke listeners — that is the dispatcher's job.
16
16
  * Inspired by the internals of Spring Modulith's Event Publication
17
17
  * Registry.
18
18
  */
@@ -28,7 +28,7 @@ const publication_status_1 = require("../types/publication-status");
28
28
  * `COMPLETED` / `FAILED` → `RESUBMITTED`);
29
29
  * - hand out deserialized event payloads ready for listener invocation.
30
30
  *
31
- * Does NOT invoke listeners — that is the dispatcher's job (Phase 5.6).
31
+ * Does NOT invoke listeners — that is the dispatcher's job.
32
32
  * Inspired by the internals of Spring Modulith's Event Publication
33
33
  * Registry.
34
34
  */
@@ -1 +1 @@
1
- {"version":3,"file":"event-publication-registry.js","sourceRoot":"","sources":["../../src/registry/event-publication-registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"event-publication-registry.js","sourceRoot":"","sources":["../../src/registry/event-publication-registry.ts"],"names":[],"mappings":"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"}
@@ -22,8 +22,8 @@ export interface RegisteredOutboxListener {
22
22
  * keyed by both the listener id (for targeted dispatch / resume) and
23
23
  * the event class name (for fan-out when a new event is published).
24
24
  *
25
- * Populated at application bootstrap by the scanner (upcoming Phase 5
26
- * iteration). Stateless beyond the two index maps.
25
+ * Populated at application bootstrap by the scanner. Stateless
26
+ * beyond the two index maps.
27
27
  */
28
28
  export declare class OutboxListenerRegistry {
29
29
  private readonly listenersByEventType;
@@ -16,8 +16,8 @@ const errors_1 = require("../types/errors");
16
16
  * keyed by both the listener id (for targeted dispatch / resume) and
17
17
  * the event class name (for fan-out when a new event is published).
18
18
  *
19
- * Populated at application bootstrap by the scanner (upcoming Phase 5
20
- * iteration). Stateless beyond the two index maps.
19
+ * Populated at application bootstrap by the scanner. Stateless
20
+ * beyond the two index maps.
21
21
  */
22
22
  let OutboxListenerRegistry = class OutboxListenerRegistry {
23
23
  listenersByEventType = new Map();
@@ -19,15 +19,22 @@ import { type OutboxDataSourceNames } from '../dispatcher/outbox-event-publisher
19
19
  * source-level clarity.
20
20
  */
21
21
  export declare const OUTBOX_LISTENER_REGISTRAR_TOKEN: unique symbol;
22
- /** Shape of an entry registered through the structural registrar port. */
23
- interface RegistrarListenerEntry {
22
+ /**
23
+ * Shape of an entry registered through the structural registrar port.
24
+ *
25
+ * Exported because it is the parameter type of the public
26
+ * {@link MultiDsOutboxListenerRegistrar.register} — without it a consumer
27
+ * cannot name what that method takes. Flagged by api-extractor's
28
+ * `ae-forgotten-export`.
29
+ */
30
+ export interface RegistrarListenerEntry {
24
31
  readonly id: string;
25
32
  readonly eventType: string;
26
33
  readonly invoke: (event: unknown) => Promise<void>;
27
34
  }
28
35
  /**
29
36
  * Multi-dataSource implementation of the cqrs package's
30
- * `OutboxListenerRegistrar` structural port (Phase 14.3.1).
37
+ * `OutboxListenerRegistrar` structural port.
31
38
  *
32
39
  * Walks every per-dataSource {@link EventTypeRegistry} to resolve
33
40
  * which dataSource owns each incoming listener's event class, then
@@ -74,5 +81,4 @@ export declare class MultiDsOutboxListenerRegistrar {
74
81
  */
75
82
  private collectEventTypeRegistries;
76
83
  }
77
- export {};
78
84
  //# sourceMappingURL=multi-ds-listener-registrar.d.ts.map
@@ -40,7 +40,7 @@ const token_utils_1 = require("../tokens/token-utils");
40
40
  exports.OUTBOX_LISTENER_REGISTRAR_TOKEN = Symbol.for('@nestjs-transactional/cqrs/outbox-listener-registrar');
41
41
  /**
42
42
  * Multi-dataSource implementation of the cqrs package's
43
- * `OutboxListenerRegistrar` structural port (Phase 14.3.1).
43
+ * `OutboxListenerRegistrar` structural port.
44
44
  *
45
45
  * Walks every per-dataSource {@link EventTypeRegistry} to resolve
46
46
  * which dataSource owns each incoming listener's event class, then
@@ -1 +1 @@
1
- {"version":3,"file":"multi-ds-listener-registrar.js","sourceRoot":"","sources":["../../src/registry/multi-ds-listener-registrar.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAA4D;AAC5D,uCAAyC;AAEzC,iFAG8C;AAE9C,8EAAwF;AACxF,uDAG+B;AAI/B;;;;;;;;;;;;;;;;;GAiBG;AACU,QAAA,+BAA+B,GAAG,MAAM,CAAC,GAAG,CACvD,sDAAsD,CACvD,CAAC;AASF;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEI,IAAM,8BAA8B,sCAApC,MAAM,8BAA8B;IAItB;IAEA;IALF,MAAM,GAAG,IAAI,eAAM,CAAC,gCAA8B,CAAC,IAAI,CAAC,CAAC;IAE1E,YACmB,SAAoB,EAEpB,eAAsC;QAFtC,cAAS,GAAT,SAAS,CAAW;QAEpB,oBAAe,GAAf,eAAe,CAAuB;IACtD,CAAC;IAEJ;;;;;OAKG;IACH,QAAQ,CAAC,QAAgC;QACvC,MAAM,mBAAmB,GAAG,IAAI,CAAC,0BAA0B,EAAE,CAAC;QAC9D,MAAM,UAAU,GAAG,IAAA,sDAAgC,EACjD,QAAQ,CAAC,SAAS,EAClB,mBAAmB,CACpB,CAAC;QAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CACjC,IAAA,4CAA8B,EAAC,UAAU,CAAC,EAC1C,EAAE,MAAM,EAAE,KAAK,EAAE,CAClB,CAAC;QACF,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAE5B,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,uBAAuB,QAAQ,CAAC,EAAE,gBAAgB,QAAQ,CAAC,SAAS,mBAAmB,UAAU,GAAG,CACrG,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACK,0BAA0B;QAChC,MAAM,UAAU,GAAG,IAAI,GAAG,EAA6B,CAAC;QACxD,KAAK,MAAM,UAAU,IAAI,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,EAAE,CAAC;YACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CACjC,IAAA,uCAAyB,EAAC,UAAU,CAAC,EACrC,EAAE,MAAM,EAAE,KAAK,EAAE,CAClB,CAAC;YACF,UAAU,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QACvC,CAAC;QACD,OAAO,UAAU,CAAC;IACpB,CAAC;CACF,CAAA;AAnDY,wEAA8B;yCAA9B,8BAA8B;IAD1C,IAAA,mBAAU,GAAE;IAMR,WAAA,IAAA,eAAM,EAAC,iDAAwB,CAAC,CAAA;qCADL,gBAAS;GAJ5B,8BAA8B,CAmD1C"}
1
+ {"version":3,"file":"multi-ds-listener-registrar.js","sourceRoot":"","sources":["../../src/registry/multi-ds-listener-registrar.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAA4D;AAC5D,uCAAyC;AAEzC,iFAG8C;AAE9C,8EAAwF;AACxF,uDAAkG;AAIlG;;;;;;;;;;;;;;;;;GAiBG;AACU,QAAA,+BAA+B,GAAG,MAAM,CAAC,GAAG,CACvD,sDAAsD,CACvD,CAAC;AAgBF;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEI,IAAM,8BAA8B,sCAApC,MAAM,8BAA8B;IAItB;IAEA;IALF,MAAM,GAAG,IAAI,eAAM,CAAC,gCAA8B,CAAC,IAAI,CAAC,CAAC;IAE1E,YACmB,SAAoB,EAEpB,eAAsC;QAFtC,cAAS,GAAT,SAAS,CAAW;QAEpB,oBAAe,GAAf,eAAe,CAAuB;IACtD,CAAC;IAEJ;;;;;OAKG;IACH,QAAQ,CAAC,QAAgC;QACvC,MAAM,mBAAmB,GAAG,IAAI,CAAC,0BAA0B,EAAE,CAAC;QAC9D,MAAM,UAAU,GAAG,IAAA,sDAAgC,EAAC,QAAQ,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;QAE7F,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CACjC,IAAA,4CAA8B,EAAC,UAAU,CAAC,EAC1C,EAAE,MAAM,EAAE,KAAK,EAAE,CAClB,CAAC;QACF,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAE5B,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,uBAAuB,QAAQ,CAAC,EAAE,gBAAgB,QAAQ,CAAC,SAAS,mBAAmB,UAAU,GAAG,CACrG,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACK,0BAA0B;QAChC,MAAM,UAAU,GAAG,IAAI,GAAG,EAA6B,CAAC;QACxD,KAAK,MAAM,UAAU,IAAI,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,EAAE,CAAC;YACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CACjC,IAAA,uCAAyB,EAAC,UAAU,CAAC,EACrC,EAAE,MAAM,EAAE,KAAK,EAAE,CAClB,CAAC;YACF,UAAU,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QACvC,CAAC;QACD,OAAO,UAAU,CAAC;IACpB,CAAC;CACF,CAAA;AAhDY,wEAA8B;yCAA9B,8BAA8B;IAD1C,IAAA,mBAAU,GAAE;IAMR,WAAA,IAAA,eAAM,EAAC,iDAAwB,CAAC,CAAA;qCADL,gBAAS;GAJ5B,8BAA8B,CAgD1C"}
@@ -9,7 +9,7 @@ import { type OutboxDataSourceNames } from '../dispatcher/outbox-event-publisher
9
9
  * the per-dataSource {@link OutboxListenerRegistry} that owns each
10
10
  * decorated event class.
11
11
  *
12
- * **Per-dataSource routing (Phase 14.3.1).** Multi-`OutboxModule.forRoot`
12
+ * **Per-dataSource routing.** Multi-`OutboxModule.forRoot`
13
13
  * deployments register events to per-DS `EventTypeRegistry`
14
14
  * instances via `OutboxModule.forFeature(events, { dataSource })`.
15
15
  * The scanner walks every per-DS `EventTypeRegistry`, resolves which
@@ -30,7 +30,7 @@ const errors_1 = require("../types/errors");
30
30
  * the per-dataSource {@link OutboxListenerRegistry} that owns each
31
31
  * decorated event class.
32
32
  *
33
- * **Per-dataSource routing (Phase 14.3.1).** Multi-`OutboxModule.forRoot`
33
+ * **Per-dataSource routing.** Multi-`OutboxModule.forRoot`
34
34
  * deployments register events to per-DS `EventTypeRegistry`
35
35
  * instances via `OutboxModule.forFeature(events, { dataSource })`.
36
36
  * The scanner walks every per-DS `EventTypeRegistry`, resolves which
@@ -1 +1 @@
1
- {"version":3,"file":"outbox-listener-scanner.js","sourceRoot":"","sources":["../../src/registry/outbox-listener-scanner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"outbox-listener-scanner.js","sourceRoot":"","sources":["../../src/registry/outbox-listener-scanner.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAiNA,8CAEC;AAnND,2CAA0F;AAC1F,uCAA2D;AAC3D,qDAAiF;AAEjF,mGAA+F;AAC/F,iFAG8C;AAE9C,8EAAwF;AACxF,uDAAkG;AAClG,4CAA8C;AAM9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEI,IAAM,qBAAqB,6BAA3B,MAAM,qBAAqB;IAIb;IACA;IAEA;IACA;IAPF,MAAM,GAAG,IAAI,eAAM,CAAC,uBAAqB,CAAC,IAAI,CAAC,CAAC;IAEjE,YACmB,SAA2B,EAC3B,SAAoB,EAEpB,eAAsC,EACtC,kBAAsC;QAJtC,cAAS,GAAT,SAAS,CAAkB;QAC3B,cAAS,GAAT,SAAS,CAAW;QAEpB,oBAAe,GAAf,eAAe,CAAuB;QACtC,uBAAkB,GAAlB,kBAAkB,CAAoB;IACtD,CAAC;IAEJ,YAAY;QACV,MAAM,mBAAmB,GAAG,IAAI,CAAC,0BAA0B,EAAE,CAAC;QAC9D,MAAM,kBAAkB,GAAG,IAAI,CAAC,yBAAyB,EAAE,CAAC;QAE5D,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,CAAC;QAEhD,KAAK,MAAM,OAAO,IAAI,SAAS,EAAE,CAAC;YAChC,IACE,OAAO,CAAC,QAAQ,KAAK,IAAI;gBACzB,OAAO,OAAO,CAAC,QAAQ,KAAK,UAAU;gBACtC,OAAO,CAAC,QAAQ,KAAK,IAAI;gBACzB,OAAO,CAAC,QAAQ,KAAK,SAAS,EAC9B,CAAC;gBACD,SAAS;YACX,CAAC;YAED,MAAM,QAAQ,GAAG,IAAA,gEAA8B,EAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YAClE,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC3B,SAAS;YACX,CAAC;YAED,MAAM,SAAS,GAAI,OAAO,CAAC,QAA8B,CAAC,IAAI,IAAI,WAAW,CAAC;YAC9E,MAAM,QAAQ,GAAW,OAAO,CAAC,QAAkB,CAAC;YACpD,MAAM,SAAS,GAAI,QAAoC,CAAC,MAAM,CAAC;YAC/D,IAAI,OAAO,SAAS,KAAK,UAAU,EAAE,CAAC;gBACpC,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,2BAA2B,SAAS,+CAA+C,CACpF,CAAC;gBACF,SAAS;YACX,CAAC;YAED,MAAM,UAAU,GAAG,IAAI,CAAC,wBAAwB,CAC9C,SAAS,EACT,QAAQ,CAAC,UAAU,EACnB,mBAAmB,CACpB,CAAC;YACF,MAAM,QAAQ,GAAG,kBAAkB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YACpD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC3B,4DAA4D;gBAC5D,2DAA2D;gBAC3D,iDAAiD;gBACjD,MAAM,IAAI,oBAAW,CACnB,2BAA2B,SAAS,6CAA6C;oBAC/E,eAAe,UAAU,oDAAoD,CAChF,CAAC;YACJ,CAAC;YAED,MAAM,WAAW,GAAI,SAAkC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACvE,MAAM,OAAO,GAAG,IAAI,CAAC,kBAAkB,CAAC;YACxC,MAAM,EAAE,cAAc,EAAE,GAAG,QAAQ,CAAC;YAEpC,MAAM,MAAM,GAAG,KAAK,EAAE,KAAc,EAAiB,EAAE;gBACrD,IAAI,cAAc,EAAE,CAAC;oBACnB,MAAM,OAAO,CAAC,GAAG,CAAC,EAAE,WAAW,EAAE,sBAAe,CAAC,YAAY,EAAE,EAAE,KAAK,IAAI,EAAE;wBAC1E,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;oBAC3B,CAAC,CAAC,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACN,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;gBAC3B,CAAC;YACH,CAAC,CAAC;YAEF,MAAM,MAAM,GAAG,QAAQ,CAAC,EAAE,IAAI,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC;YAExD,KAAK,MAAM,SAAS,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;gBAC5C,MAAM,UAAU,GAAG,iBAAiB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;gBACxD,QAAQ,CAAC,QAAQ,CAAC;oBAChB,EAAE,EAAE,UAAU;oBACd,SAAS,EAAE,SAAS,CAAC,IAAI;oBACzB,MAAM;iBACP,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACK,wBAAwB,CAC9B,SAAiB,EACjB,UAA2B,EAC3B,mBAA2D;QAE3D,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAAkB,CAAC;QACrD,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,MAAM,UAAU,GAAG,IAAA,sDAAgC,EAAC,SAAS,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC;YACzF,kBAAkB,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QACrD,CAAC;QAED,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,kBAAkB,CAAC,MAAM,EAAE,CAAC,CAAC;QAC/D,IAAI,iBAAiB,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YAC/B,MAAM,SAAS,GAAG,CAAC,GAAG,kBAAkB,CAAC;iBACtC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,KAAK,SAAS,OAAO,UAAU,GAAG,CAAC;iBACpE,IAAI,CAAC,IAAI,CAAC,CAAC;YACd,MAAM,IAAI,oBAAW,CACnB,2BAA2B,SAAS,wCAAwC,SAAS,IAAI;gBACvF,2DAA2D;gBAC3D,oFAAoF;gBACpF,8DAA8D;gBAC9D,4EAA4E,CAC/E,CAAC;QACJ,CAAC;QACD,6DAA6D;QAC7D,8DAA8D;QAC9D,oEAAoE;QACpE,OAAO,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAE,CAAC;IACpC,CAAC;IAEO,0BAA0B;QAChC,MAAM,UAAU,GAAG,IAAI,GAAG,EAA6B,CAAC;QACxD,KAAK,MAAM,UAAU,IAAI,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,EAAE,CAAC;YACrD,UAAU,CAAC,GAAG,CACZ,UAAU,EACV,IAAI,CAAC,SAAS,CAAC,GAAG,CAAoB,IAAA,uCAAyB,EAAC,UAAU,CAAC,EAAE;gBAC3E,MAAM,EAAE,KAAK;aACd,CAAC,CACH,CAAC;QACJ,CAAC;QACD,OAAO,UAAU,CAAC;IACpB,CAAC;IAEO,yBAAyB;QAC/B,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkC,CAAC;QAC7D,KAAK,MAAM,UAAU,IAAI,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,EAAE,CAAC;YACrD,UAAU,CAAC,GAAG,CACZ,UAAU,EACV,IAAI,CAAC,SAAS,CAAC,GAAG,CAAyB,IAAA,4CAA8B,EAAC,UAAU,CAAC,EAAE;gBACrF,MAAM,EAAE,KAAK;aACd,CAAC,CACH,CAAC;QACJ,CAAC;QACD,OAAO,UAAU,CAAC;IACpB,CAAC;CACF,CAAA;AAlJY,sDAAqB;gCAArB,qBAAqB;IADjC,IAAA,mBAAU,GAAE;IAOR,WAAA,IAAA,eAAM,EAAC,iDAAwB,CAAC,CAAA;qCAFL,uBAAgB;QAChB,gBAAS,UAGA,yBAAkB;GAR9C,qBAAqB,CAkJjC;AAED;;;;;GAKG;AACH,SAAgB,iBAAiB,CAAC,MAAc,EAAE,SAAe;IAC/D,OAAO,GAAG,MAAM,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC;AACvC,CAAC"}
@@ -64,15 +64,35 @@ export interface EventPublicationRepository {
64
64
  * Atomically claim a publication: transition `PUBLISHED` or
65
65
  * `RESUBMITTED` → `PROCESSING` (and increment `completionAttempts`)
66
66
  * iff the current status is one of those. Returns `true` when the
67
- * claim succeeded, `false` otherwise — used by the dispatcher to
68
- * prevent double-processing across workers.
67
+ * claim succeeded, `false` otherwise.
68
+ *
69
+ * **This method carries the SPI's whole concurrency guarantee.** It is
70
+ * what prevents double-processing across workers, so the status check
71
+ * and the transition MUST be one indivisible operation — a conditional
72
+ * `UPDATE ... WHERE status IN (...)` reporting affected-row count, a
73
+ * `findOneAndUpdate` with the status in the filter, or an equivalent
74
+ * compare-and-set. A read-then-write implementation is incorrect: two
75
+ * workers would both observe `PUBLISHED` and both dispatch.
76
+ *
77
+ * See DD-025.
69
78
  */
70
79
  tryClaim(id: string): Promise<boolean>;
71
80
  /**
72
81
  * Find publications ready for processing (status `PUBLISHED` or
73
- * `RESUBMITTED`). Production implementations should use
74
- * `SELECT ... FOR UPDATE SKIP LOCKED` (or equivalent) to be safe
75
- * against concurrent workers.
82
+ * `RESUBMITTED`), oldest first.
83
+ *
84
+ * Deliberately NOT exclusive: implementations need not lock rows or
85
+ * hand out disjoint sets, and concurrent workers may receive
86
+ * overlapping results. Correctness comes from {@link tryClaim} — a
87
+ * worker that loses the claim skips the publication without invoking
88
+ * its listener, so overlap costs a wasted read, never a duplicate
89
+ * dispatch.
90
+ *
91
+ * Row-locking implementations (`SELECT ... FOR UPDATE SKIP LOCKED`)
92
+ * are permitted but not expected, and neither shipped implementation
93
+ * uses one: a pessimistic lock has to be held by a transaction that
94
+ * spans the listener invocation, which is unsafe for long-running
95
+ * listeners. See DD-025.
76
96
  */
77
97
  findReadyForProcessing(limit: number): Promise<EventPublication[]>;
78
98
  /**
@@ -80,7 +100,18 @@ export interface EventPublicationRepository {
80
100
  * strictly before `beforeDate`. Used by the staleness monitor.
81
101
  */
82
102
  findStale(beforeDate: Date, statuses: PublicationStatus[]): Promise<EventPublication[]>;
83
- /** Find all completed publications, with optional pagination / cutoff. */
103
+ /**
104
+ * Find all completed publications, with optional pagination / cutoff,
105
+ * ordered by `completionDate` **oldest first**.
106
+ *
107
+ * The ordering is part of the contract because `limit` makes it one.
108
+ * A retention job asks for a bounded page and deletes it; if the page
109
+ * came back newest-first, a job that cannot keep up with the
110
+ * completion rate would delete only the recent rows and never reach
111
+ * the old ones, which is the exact opposite of what a retention window
112
+ * promises. Draining from the oldest end degrades correctly instead:
113
+ * falling behind shrinks the backlog, it does not strand its tail.
114
+ */
84
115
  findCompleted(options?: FindCompletedOptions): Promise<EventPublication[]>;
85
116
  /**
86
117
  * Find all incomplete publications (status other than `COMPLETED`).
@@ -1 +1 @@
1
- {"version":3,"file":"event-publication-repository.js","sourceRoot":"","sources":["../../src/repository/event-publication-repository.ts"],"names":[],"mappings":";;;AAiIA,kEAAkE;AACrD,QAAA,4BAA4B,GAAG,MAAM,CAAC,8BAA8B,CAAC,CAAC"}
1
+ {"version":3,"file":"event-publication-repository.js","sourceRoot":"","sources":["../../src/repository/event-publication-repository.ts"],"names":[],"mappings":";;;AA4JA,kEAAkE;AACrD,QAAA,4BAA4B,GAAG,MAAM,CAAC,8BAA8B,CAAC,CAAC"}
@@ -6,7 +6,7 @@ import type { EventTypeRegistry } from './event-type-registry';
6
6
  * the event-type — otherwise throws {@link OutboxError} with an
7
7
  * actionable message.
8
8
  *
9
- * Single source of truth shared by three consumers (Phase 14.3.1):
9
+ * Single source of truth shared by three consumers:
10
10
  *
11
11
  * - {@link OutboxEventPublisher.resolveDataSource} — smart-facade
12
12
  * publisher routes events to the dataSource that registered them.
@@ -9,7 +9,7 @@ const errors_1 = require("../types/errors");
9
9
  * the event-type — otherwise throws {@link OutboxError} with an
10
10
  * actionable message.
11
11
  *
12
- * Single source of truth shared by three consumers (Phase 14.3.1):
12
+ * Single source of truth shared by three consumers:
13
13
  *
14
14
  * - {@link OutboxEventPublisher.resolveDataSource} — smart-facade
15
15
  * publisher routes events to the dataSource that registered them.
@@ -1 +1 @@
1
- {"version":3,"file":"json-event-serializer.js","sourceRoot":"","sources":["../../src/serialization/json-event-serializer.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAE5C,4CAA2E;AAG3E,+DAA0D;AAE1D;;;;;;;;;;GAUG;AAEI,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IACD;IAA7B,YAA6B,QAA2B;QAA3B,aAAQ,GAAR,QAAQ,CAAmB;IAAG,CAAC;IAE5D,SAAS,CAAC,KAAc;QACtB,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACxC,MAAM,IAAI,2BAAkB,CAAC,gCAAgC,OAAO,KAAK,EAAE,CAAC,CAAC;QAC/E,CAAC;QACD,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,2BAAkB,CAC1B,8BAA+B,GAAa,CAAC,OAAO,EAAE,CACvD,CAAC;QACJ,CAAC;IACH,CAAC;IAED,WAAW,CAAC,UAAkB,EAAE,SAAiB;QAC/C,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAEhD,IAAI,IAAa,CAAC;QAClB,IAAI,CAAC;YACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,6BAAoB,CAC5B,gCAAgC,SAAS,MAAO,GAAa,CAAC,OAAO,EAAE,CACxE,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,SAAS,GAAW,UAAU,CAAC,SAAmB,CAAC;QACzD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAW,EAAE,IAAI,CAAC,CAAC;IACjE,CAAC;CACF,CAAA;AAnCY,kDAAmB;8BAAnB,mBAAmB;IAD/B,IAAA,mBAAU,GAAE;qCAE4B,uCAAiB;GAD7C,mBAAmB,CAmC/B"}
1
+ {"version":3,"file":"json-event-serializer.js","sourceRoot":"","sources":["../../src/serialization/json-event-serializer.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAE5C,4CAA2E;AAG3E,+DAA0D;AAE1D;;;;;;;;;;GAUG;AAEI,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IACD;IAA7B,YAA6B,QAA2B;QAA3B,aAAQ,GAAR,QAAQ,CAAmB;IAAG,CAAC;IAE5D,SAAS,CAAC,KAAc;QACtB,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACxC,MAAM,IAAI,2BAAkB,CAAC,gCAAgC,OAAO,KAAK,EAAE,CAAC,CAAC;QAC/E,CAAC;QACD,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,2BAAkB,CAAC,8BAA+B,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;IAED,WAAW,CAAC,UAAkB,EAAE,SAAiB;QAC/C,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAEhD,IAAI,IAAa,CAAC;QAClB,IAAI,CAAC;YACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,6BAAoB,CAC5B,gCAAgC,SAAS,MAAO,GAAa,CAAC,OAAO,EAAE,CACxE,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,SAAS,GAAW,UAAU,CAAC,SAAmB,CAAC;QACzD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAW,EAAE,IAAI,CAAC,CAAC;IACjE,CAAC;CACF,CAAA;AAjCY,kDAAmB;8BAAnB,mBAAmB;IAD/B,IAAA,mBAAU,GAAE;qCAE4B,uCAAiB;GAD7C,mBAAmB,CAiC/B"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Default drain budget for the outbox background workers, in
3
+ * milliseconds.
4
+ *
5
+ * Sized against platform grace periods rather than against any
6
+ * particular listener: Kubernetes' `terminationGracePeriodSeconds`
7
+ * defaults to 30s, and the rest of the shutdown path (closing the
8
+ * connection pool, flushing logs) needs room after the drain. 10s
9
+ * leaves that margin.
10
+ */
11
+ export declare const DEFAULT_DRAIN_TIMEOUT_MS = 10000;
12
+ /**
13
+ * Await `inFlight`, giving up after `timeoutMs`.
14
+ *
15
+ * Resolves `true` when the work finished within the budget and `false`
16
+ * when the budget ran out first. A `timeoutMs` of `0` means "do not
17
+ * wait at all" and reports `false` without awaiting anything.
18
+ *
19
+ * The abandoned work is NOT cancelled — there is no safe way to
20
+ * interrupt a half-finished listener invocation or SQL statement. The
21
+ * caller's contract is weaker and deliberately so: shutdown proceeds,
22
+ * and whatever was left mid-flight is recovered on the next boot by
23
+ * the staleness monitor / startup recovery. Blocking shutdown
24
+ * indefinitely on user code would be the worse failure — a deployment
25
+ * that never completes.
26
+ *
27
+ * Never rejects: both the processor's `processBatch` and the monitor's
28
+ * `checkStaleness` already swallow their own failures, and a drain that
29
+ * threw would turn an orderly shutdown into an unhandled rejection.
30
+ */
31
+ export declare function drainWithTimeout(inFlight: Promise<unknown>, timeoutMs: number): Promise<boolean>;
32
+ //# sourceMappingURL=drain.d.ts.map
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_DRAIN_TIMEOUT_MS = void 0;
4
+ exports.drainWithTimeout = drainWithTimeout;
5
+ /**
6
+ * Default drain budget for the outbox background workers, in
7
+ * milliseconds.
8
+ *
9
+ * Sized against platform grace periods rather than against any
10
+ * particular listener: Kubernetes' `terminationGracePeriodSeconds`
11
+ * defaults to 30s, and the rest of the shutdown path (closing the
12
+ * connection pool, flushing logs) needs room after the drain. 10s
13
+ * leaves that margin.
14
+ */
15
+ exports.DEFAULT_DRAIN_TIMEOUT_MS = 10_000;
16
+ /**
17
+ * Await `inFlight`, giving up after `timeoutMs`.
18
+ *
19
+ * Resolves `true` when the work finished within the budget and `false`
20
+ * when the budget ran out first. A `timeoutMs` of `0` means "do not
21
+ * wait at all" and reports `false` without awaiting anything.
22
+ *
23
+ * The abandoned work is NOT cancelled — there is no safe way to
24
+ * interrupt a half-finished listener invocation or SQL statement. The
25
+ * caller's contract is weaker and deliberately so: shutdown proceeds,
26
+ * and whatever was left mid-flight is recovered on the next boot by
27
+ * the staleness monitor / startup recovery. Blocking shutdown
28
+ * indefinitely on user code would be the worse failure — a deployment
29
+ * that never completes.
30
+ *
31
+ * Never rejects: both the processor's `processBatch` and the monitor's
32
+ * `checkStaleness` already swallow their own failures, and a drain that
33
+ * threw would turn an orderly shutdown into an unhandled rejection.
34
+ */
35
+ async function drainWithTimeout(inFlight, timeoutMs) {
36
+ if (timeoutMs <= 0) {
37
+ return false;
38
+ }
39
+ let timer;
40
+ const expired = new Promise((resolve) => {
41
+ timer = setTimeout(() => resolve(false), timeoutMs);
42
+ // Do not hold the event loop open purely to police the deadline —
43
+ // if everything else has finished, the process should be free to
44
+ // exit.
45
+ timer.unref?.();
46
+ });
47
+ try {
48
+ return await Promise.race([inFlight.then(() => true), expired]);
49
+ }
50
+ finally {
51
+ if (timer !== undefined) {
52
+ clearTimeout(timer);
53
+ }
54
+ }
55
+ }
56
+ //# sourceMappingURL=drain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drain.js","sourceRoot":"","sources":["../../src/shutdown/drain.ts"],"names":[],"mappings":";;;AA+BA,4CAwBC;AAvDD;;;;;;;;;GASG;AACU,QAAA,wBAAwB,GAAG,MAAM,CAAC;AAE/C;;;;;;;;;;;;;;;;;;GAkBG;AACI,KAAK,UAAU,gBAAgB,CACpC,QAA0B,EAC1B,SAAiB;IAEjB,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;QACnB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,KAAiC,CAAC;IACtC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAQ,CAAC,OAAO,EAAE,EAAE;QAC7C,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC,CAAC;QACpD,kEAAkE;QAClE,iEAAiE;QACjE,QAAQ;QACR,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IAClE,CAAC;YAAS,CAAC;QACT,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,YAAY,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;AACH,CAAC"}