@nestjs-transactional/outbox 1.0.0 → 2.0.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 +38 -5
- package/dist/api/completed-event-publications.d.ts +2 -2
- package/dist/api/completed-event-publications.js +6 -9
- package/dist/api/completed-event-publications.js.map +1 -1
- package/dist/api/failed-event-publications.d.ts +3 -3
- package/dist/api/failed-event-publications.js +10 -13
- package/dist/api/failed-event-publications.js.map +1 -1
- package/dist/api/incomplete-event-publications.d.ts +3 -3
- package/dist/api/incomplete-event-publications.js +11 -14
- package/dist/api/incomplete-event-publications.js.map +1 -1
- package/dist/decorators/inject-decorators.js +12 -24
- package/dist/decorators/inject-decorators.js.map +1 -1
- package/dist/decorators/outbox-events-handler.decorator.js +6 -11
- package/dist/decorators/outbox-events-handler.decorator.js.map +1 -1
- package/dist/dispatcher/data-source-outbox-publisher.d.ts +2 -2
- package/dist/dispatcher/data-source-outbox-publisher.js +7 -11
- package/dist/dispatcher/data-source-outbox-publisher.js.map +1 -1
- package/dist/dispatcher/event-publication-processor.d.ts +5 -5
- package/dist/dispatcher/event-publication-processor.js +18 -21
- package/dist/dispatcher/event-publication-processor.js.map +1 -1
- package/dist/dispatcher/outbox-event-publisher.js +16 -19
- package/dist/dispatcher/outbox-event-publisher.js.map +1 -1
- package/dist/dispatcher/processor-options.d.ts +1 -1
- package/dist/dispatcher/processor-options.js +5 -8
- package/dist/dispatcher/processor-options.js.map +1 -1
- package/dist/externalization/describe-thrown.d.ts +20 -0
- package/dist/externalization/describe-thrown.js +46 -0
- package/dist/externalization/describe-thrown.js.map +1 -0
- package/dist/externalization/errors.d.ts +1 -1
- package/dist/externalization/errors.js +2 -6
- package/dist/externalization/errors.js.map +1 -1
- package/dist/externalization/event-externalizer.d.ts +1 -1
- package/dist/externalization/event-externalizer.js +1 -4
- package/dist/externalization/event-externalizer.js.map +1 -1
- package/dist/externalization/externalization-registry.d.ts +3 -3
- package/dist/externalization/externalization-registry.js +10 -13
- package/dist/externalization/externalization-registry.js.map +1 -1
- package/dist/externalization/externalized.decorator.js +6 -11
- package/dist/externalization/externalized.decorator.js.map +1 -1
- package/dist/externalization/types.js +1 -2
- package/dist/index.d.ts +43 -40
- package/dist/index.js +41 -61
- package/dist/index.js.map +1 -1
- package/dist/interfaces/outbox-event-handler.interface.js +1 -2
- package/dist/module/outbox-processing.module.d.ts +1 -1
- package/dist/module/outbox-processing.module.js +12 -9
- package/dist/module/outbox-processing.module.js.map +1 -1
- package/dist/module/outbox.module.d.ts +15 -8
- package/dist/module/outbox.module.js +179 -145
- package/dist/module/outbox.module.js.map +1 -1
- package/dist/recovery/outbox-cleanup-scheduler.d.ts +56 -0
- package/dist/recovery/outbox-cleanup-scheduler.js +136 -0
- package/dist/recovery/outbox-cleanup-scheduler.js.map +1 -0
- package/dist/recovery/outbox-retry-scheduler.d.ts +2 -2
- package/dist/recovery/outbox-retry-scheduler.js +11 -14
- package/dist/recovery/outbox-retry-scheduler.js.map +1 -1
- package/dist/recovery/staleness-monitor.d.ts +2 -2
- package/dist/recovery/staleness-monitor.js +14 -17
- package/dist/recovery/staleness-monitor.js.map +1 -1
- package/dist/recovery/startup-recovery.d.ts +1 -1
- package/dist/recovery/startup-recovery.js +11 -14
- package/dist/recovery/startup-recovery.js.map +1 -1
- package/dist/registry/event-publication-registry.d.ts +4 -4
- package/dist/registry/event-publication-registry.js +17 -20
- package/dist/registry/event-publication-registry.js.map +1 -1
- package/dist/registry/listener-registry.js +6 -9
- package/dist/registry/listener-registry.js.map +1 -1
- package/dist/registry/multi-ds-listener-registrar.d.ts +1 -1
- package/dist/registry/multi-ds-listener-registrar.js +15 -18
- package/dist/registry/multi-ds-listener-registrar.js.map +1 -1
- package/dist/registry/outbox-listener-scanner.d.ts +1 -1
- package/dist/registry/outbox-listener-scanner.js +23 -27
- package/dist/registry/outbox-listener-scanner.js.map +1 -1
- package/dist/repository/event-publication-repository.d.ts +14 -3
- package/dist/repository/event-publication-repository.js +1 -4
- package/dist/repository/event-publication-repository.js.map +1 -1
- package/dist/serialization/event-serializer.js +1 -4
- package/dist/serialization/event-serializer.js.map +1 -1
- package/dist/serialization/event-type-registry.js +5 -8
- package/dist/serialization/event-type-registry.js.map +1 -1
- package/dist/serialization/event-type-resolver.d.ts +1 -1
- package/dist/serialization/event-type-resolver.js +4 -7
- package/dist/serialization/event-type-resolver.js.map +1 -1
- package/dist/serialization/json-event-serializer.d.ts +2 -2
- package/dist/serialization/json-event-serializer.js +10 -13
- package/dist/serialization/json-event-serializer.js.map +1 -1
- package/dist/shutdown/drain.js +2 -6
- package/dist/shutdown/drain.js.map +1 -1
- package/dist/testing/assertable-published-events.d.ts +1 -1
- package/dist/testing/assertable-published-events.js +8 -13
- package/dist/testing/assertable-published-events.js.map +1 -1
- package/dist/testing/in-memory-repository.d.ts +3 -3
- package/dist/testing/in-memory-repository.js +32 -25
- package/dist/testing/in-memory-repository.js.map +1 -1
- package/dist/testing/index.d.ts +3 -3
- package/dist/testing/index.js +3 -19
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/published-events.d.ts +3 -3
- package/dist/testing/published-events.js +11 -14
- package/dist/testing/published-events.js.map +1 -1
- package/dist/tokens/index.d.ts +1 -1
- package/dist/tokens/index.js +1 -13
- package/dist/tokens/index.js.map +1 -1
- package/dist/tokens/token-utils.js +10 -21
- package/dist/tokens/token-utils.js.map +1 -1
- package/dist/types/cleanup-config.d.ts +59 -0
- package/dist/types/cleanup-config.js +14 -0
- package/dist/types/cleanup-config.js.map +1 -0
- package/dist/types/completion-mode.js +2 -5
- package/dist/types/completion-mode.js.map +1 -1
- package/dist/types/errors.d.ts +1 -1
- package/dist/types/errors.js +7 -16
- package/dist/types/errors.js.map +1 -1
- package/dist/types/event-publication.d.ts +1 -1
- package/dist/types/event-publication.js +1 -2
- package/dist/types/publication-status.js +2 -5
- package/dist/types/publication-status.js.map +1 -1
- package/dist/types/resubmission-options.d.ts +1 -1
- package/dist/types/resubmission-options.js +1 -5
- package/dist/types/resubmission-options.js.map +1 -1
- package/dist/types/retry-config.js +3 -6
- package/dist/types/retry-config.js.map +1 -1
- package/dist/types/staleness-config.js +3 -6
- package/dist/types/staleness-config.js.map +1 -1
- package/package.json +21 -19
package/README.md
CHANGED
|
@@ -32,6 +32,20 @@ pnpm add @nestjs-transactional/outbox @nestjs-transactional/core
|
|
|
32
32
|
pnpm add @nestjs-transactional/outbox-typeorm # a persistence backend
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
+
## Module format
|
|
36
|
+
|
|
37
|
+
This package ships **ESM only**, matching NestJS 12, which is ESM-only
|
|
38
|
+
across its own packages. There is no CommonJS build.
|
|
39
|
+
|
|
40
|
+
A CommonJS application still works: Node loads ESM from `require()`
|
|
41
|
+
since 22.12.0, which is why `engines.node` is `>=22.13.0`. What does not
|
|
42
|
+
follow Node here is tooling with its own module loader — Jest above all,
|
|
43
|
+
which needs `NODE_OPTIONS=--experimental-vm-modules` and a few config
|
|
44
|
+
settings. The 19 example applications in the repository all run their
|
|
45
|
+
suites that way and can be copied from.
|
|
46
|
+
|
|
47
|
+
Reasoning and measurements: [ADR-022](https://github.com/igorgolovanov/nestjs-transactional/blob/main/docs/adr/022-esm-only-packaging.md).
|
|
48
|
+
|
|
35
49
|
## Quick start
|
|
36
50
|
|
|
37
51
|
```ts
|
|
@@ -135,6 +149,9 @@ OutboxModule.forRoot({
|
|
|
135
149
|
// Automatic retry, off unless you ask for it. maxAttempts counts the
|
|
136
150
|
// first delivery, so 3 means the original plus two retries.
|
|
137
151
|
retry: { maxAttempts: 3, baseDelay: 1_000, factor: 2, maxDelay: 300_000 },
|
|
152
|
+
// Retention for COMPLETED publications, also off unless asked for.
|
|
153
|
+
// 0 = off, which leaves purging to you.
|
|
154
|
+
cleanup: { interval: 3_600_000, retention: 7 * 24 * 3_600_000, batchSize: 500 },
|
|
138
155
|
});
|
|
139
156
|
```
|
|
140
157
|
|
|
@@ -148,6 +165,19 @@ stays `FAILED`; there is no separate dead-letter state, and it remains
|
|
|
148
165
|
visible and resubmittable
|
|
149
166
|
([DD-026](https://github.com/igorgolovanov/nestjs-transactional/blob/main/docs/dd/026-automatic-retry-policy.md)).
|
|
150
167
|
|
|
168
|
+
Under the default `UPDATE` completion mode a delivered publication
|
|
169
|
+
stays as an audit row and nothing removes it, so the table grows until
|
|
170
|
+
someone purges it. `cleanup` puts that purge on a timer: each pass takes
|
|
171
|
+
up to `batchSize` publications whose `completionDate` is older than
|
|
172
|
+
`retention` and deletes them. The bound matters, because the first pass
|
|
173
|
+
after enabling this on an existing deployment meets the table at its
|
|
174
|
+
largest, and one unbounded `DELETE` there is a long transaction holding
|
|
175
|
+
locks your writers need. Passes drain from the oldest end, so a job that
|
|
176
|
+
cannot keep up still shrinks the backlog rather than stranding its tail.
|
|
177
|
+
|
|
178
|
+
`completed.purge(olderThan)` is unchanged and remains the right tool for
|
|
179
|
+
a deliberate one-shot bulk purge.
|
|
180
|
+
|
|
151
181
|
Three injectable APIs for operators, matching Spring Modulith's:
|
|
152
182
|
|
|
153
183
|
```ts
|
|
@@ -193,11 +223,14 @@ await assertable.doesNotContain(OrderCancelledEvent);
|
|
|
193
223
|
`@Externalized` marks an event for forwarding after its local handlers
|
|
194
224
|
complete. The `EVENT_EXTERNALIZER` SPI is transport-agnostic;
|
|
195
225
|
`outbox-microservices` implements it over `@nestjs/microservices`.
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
broker
|
|
200
|
-
|
|
226
|
+
|
|
227
|
+
A publication is marked `COMPLETED` when the externalizer resolves,
|
|
228
|
+
and what that proves depends on the transport. Kafka and RabbitMQ wait
|
|
229
|
+
for a broker acknowledgement, so a broker that is down produces a
|
|
230
|
+
`FAILED` row the retry and resubmit machinery can act on. NATS core and
|
|
231
|
+
TCP acknowledge nothing, and gRPC cannot be used for externalization at
|
|
232
|
+
all. The per-transport table is in that package's README and in
|
|
233
|
+
[ADR-021](https://github.com/igorgolovanov/nestjs-transactional/blob/main/docs/adr/021-externalization-acknowledgement-per-transport.md).
|
|
201
234
|
|
|
202
235
|
## Documentation
|
|
203
236
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type EventPublicationRepository } from '../repository/event-publication-repository';
|
|
2
|
-
import type { EventPublication } from '../types/event-publication';
|
|
1
|
+
import { type EventPublicationRepository } from '../repository/event-publication-repository.js';
|
|
2
|
+
import type { EventPublication } from '../types/event-publication.js';
|
|
3
3
|
/**
|
|
4
4
|
* Operator-facing query + purge API for publications that have
|
|
5
5
|
* reached the terminal `COMPLETED` state. Equivalent to Spring
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
2
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
3
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -11,10 +10,8 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
11
10
|
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
11
|
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
12
|
};
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const common_1 = require("@nestjs/common");
|
|
17
|
-
const event_publication_repository_1 = require("../repository/event-publication-repository");
|
|
13
|
+
import { Inject, Injectable } from '@nestjs/common';
|
|
14
|
+
import { EVENT_PUBLICATION_REPOSITORY, } from '../repository/event-publication-repository.js';
|
|
18
15
|
/**
|
|
19
16
|
* Operator-facing query + purge API for publications that have
|
|
20
17
|
* reached the terminal `COMPLETED` state. Equivalent to Spring
|
|
@@ -49,10 +46,10 @@ let CompletedEventPublications = class CompletedEventPublications {
|
|
|
49
46
|
return this.repository.deleteCompleted(olderThan);
|
|
50
47
|
}
|
|
51
48
|
};
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
(0,
|
|
55
|
-
__param(0, (0, common_1.Inject)(event_publication_repository_1.EVENT_PUBLICATION_REPOSITORY)),
|
|
49
|
+
CompletedEventPublications = __decorate([
|
|
50
|
+
Injectable(),
|
|
51
|
+
__param(0, Inject(EVENT_PUBLICATION_REPOSITORY)),
|
|
56
52
|
__metadata("design:paramtypes", [Object])
|
|
57
53
|
], CompletedEventPublications);
|
|
54
|
+
export { CompletedEventPublications };
|
|
58
55
|
//# sourceMappingURL=completed-event-publications.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"completed-event-publications.js","sourceRoot":"","sources":["../../src/api/completed-event-publications.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"completed-event-publications.js","sourceRoot":"","sources":["../../src/api/completed-event-publications.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEpD,OAAO,EACL,4BAA4B,GAE7B,MAAM,+CAA+C,CAAC;AAGvD;;;;;;;GAOG;AAEI,IAAM,0BAA0B,GAAhC,MAAM,0BAA0B;IAGlB;IAFnB,YAEmB,UAAsC;QAAtC,eAAU,GAAV,UAAU,CAA4B;IACtD,CAAC;IAEJ;;;OAGG;IACH,KAAK,CAAC,OAAO,CAAC,OAGb;QACC,OAAO,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAChD,CAAC;IAED,0DAA0D;IAC1D,KAAK,CAAC,KAAK;QACT,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC;QACxD,OAAO,SAAS,CAAC,MAAM,CAAC;IAC1B,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,KAAK,CAAC,SAAgB;QAC1B,OAAO,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;CACF,CAAA;AA/BY,0BAA0B;IADtC,UAAU,EAAE;IAGR,WAAA,MAAM,CAAC,4BAA4B,CAAC,CAAA;;GAF5B,0BAA0B,CA+BtC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type EventPublicationRepository } from '../repository/event-publication-repository';
|
|
2
|
-
import type { EventPublication } from '../types/event-publication';
|
|
3
|
-
import { ResubmissionOptions } from '../types/resubmission-options';
|
|
1
|
+
import { type EventPublicationRepository } from '../repository/event-publication-repository.js';
|
|
2
|
+
import type { EventPublication } from '../types/event-publication.js';
|
|
3
|
+
import { ResubmissionOptions } from '../types/resubmission-options.js';
|
|
4
4
|
/**
|
|
5
5
|
* Operator-facing query + resubmit API for publications currently in
|
|
6
6
|
* the `FAILED` state. Equivalent to Spring Modulith's
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
2
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
3
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -11,12 +10,10 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
11
10
|
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
11
|
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
12
|
};
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const publication_status_1 = require("../types/publication-status");
|
|
19
|
-
const resubmission_options_1 = require("../types/resubmission-options");
|
|
13
|
+
import { Inject, Injectable } from '@nestjs/common';
|
|
14
|
+
import { EVENT_PUBLICATION_REPOSITORY, } from '../repository/event-publication-repository.js';
|
|
15
|
+
import { PublicationStatus } from '../types/publication-status.js';
|
|
16
|
+
import { ResubmissionOptions } from '../types/resubmission-options.js';
|
|
20
17
|
/**
|
|
21
18
|
* Operator-facing query + resubmit API for publications currently in
|
|
22
19
|
* the `FAILED` state. Equivalent to Spring Modulith's
|
|
@@ -51,7 +48,7 @@ let FailedEventPublications = class FailedEventPublications {
|
|
|
51
48
|
* 2. Apply the user-supplied `filter` predicate, if any.
|
|
52
49
|
* 3. Keep at most `batchSize` publications.
|
|
53
50
|
*/
|
|
54
|
-
async resubmit(options =
|
|
51
|
+
async resubmit(options = ResubmissionOptions.defaults()) {
|
|
55
52
|
const failed = await this.repository.findFailed({
|
|
56
53
|
minAge: options.minAge,
|
|
57
54
|
maxAttempts: options.maxCompletionAttempts ?? undefined,
|
|
@@ -59,17 +56,17 @@ let FailedEventPublications = class FailedEventPublications {
|
|
|
59
56
|
const filtered = options.filter !== null ? failed.filter(options.filter) : failed;
|
|
60
57
|
const toProcess = filtered.slice(0, options.batchSize);
|
|
61
58
|
for (const pub of toProcess) {
|
|
62
|
-
await this.repository.updateStatus(pub.id,
|
|
59
|
+
await this.repository.updateStatus(pub.id, PublicationStatus.RESUBMITTED, {
|
|
63
60
|
lastResubmissionDate: new Date(),
|
|
64
61
|
});
|
|
65
62
|
}
|
|
66
63
|
return toProcess.length;
|
|
67
64
|
}
|
|
68
65
|
};
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
(0,
|
|
72
|
-
__param(0, (0, common_1.Inject)(event_publication_repository_1.EVENT_PUBLICATION_REPOSITORY)),
|
|
66
|
+
FailedEventPublications = __decorate([
|
|
67
|
+
Injectable(),
|
|
68
|
+
__param(0, Inject(EVENT_PUBLICATION_REPOSITORY)),
|
|
73
69
|
__metadata("design:paramtypes", [Object])
|
|
74
70
|
], FailedEventPublications);
|
|
71
|
+
export { FailedEventPublications };
|
|
75
72
|
//# sourceMappingURL=failed-event-publications.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"failed-event-publications.js","sourceRoot":"","sources":["../../src/api/failed-event-publications.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"failed-event-publications.js","sourceRoot":"","sources":["../../src/api/failed-event-publications.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEpD,OAAO,EACL,4BAA4B,GAE7B,MAAM,+CAA+C,CAAC;AAEvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAEvE;;;;GAIG;AAEI,IAAM,uBAAuB,GAA7B,MAAM,uBAAuB;IAGf;IAFnB,YAEmB,UAAsC;QAAtC,eAAU,GAAV,UAAU,CAA4B;IACtD,CAAC;IAEJ;;;;OAIG;IACH,KAAK,CAAC,OAAO,CAAC,OAGb;QACC,OAAO,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAC7C,CAAC;IAED,uDAAuD;IACvD,KAAK,CAAC,KAAK;QACT,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC;QAClD,OAAO,MAAM,CAAC,MAAM,CAAC;IACvB,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,QAAQ,CAAC,UAA+B,mBAAmB,CAAC,QAAQ,EAAE;QAC1E,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;YAC9C,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,WAAW,EAAE,OAAO,CAAC,qBAAqB,IAAI,SAAS;SACxD,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAClF,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;QAEvD,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;YAC5B,MAAM,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,EAAE,iBAAiB,CAAC,WAAW,EAAE;gBACxE,oBAAoB,EAAE,IAAI,IAAI,EAAE;aACjC,CAAC,CAAC;QACL,CAAC;QAED,OAAO,SAAS,CAAC,MAAM,CAAC;IAC1B,CAAC;CACF,CAAA;AApDY,uBAAuB;IADnC,UAAU,EAAE;IAGR,WAAA,MAAM,CAAC,4BAA4B,CAAC,CAAA;;GAF5B,uBAAuB,CAoDnC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type EventPublicationRepository } from '../repository/event-publication-repository';
|
|
2
|
-
import type { EventPublication } from '../types/event-publication';
|
|
3
|
-
import { ResubmissionOptions } from '../types/resubmission-options';
|
|
1
|
+
import { type EventPublicationRepository } from '../repository/event-publication-repository.js';
|
|
2
|
+
import type { EventPublication } from '../types/event-publication.js';
|
|
3
|
+
import { ResubmissionOptions } from '../types/resubmission-options.js';
|
|
4
4
|
/**
|
|
5
5
|
* Operator-facing query + resubmit API for every publication that has
|
|
6
6
|
* not yet reached the terminal `COMPLETED` state. Equivalent to Spring
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
2
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
3
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -11,12 +10,10 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
11
10
|
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
11
|
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
12
|
};
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const publication_status_1 = require("../types/publication-status");
|
|
19
|
-
const resubmission_options_1 = require("../types/resubmission-options");
|
|
13
|
+
import { Inject, Injectable } from '@nestjs/common';
|
|
14
|
+
import { EVENT_PUBLICATION_REPOSITORY, } from '../repository/event-publication-repository.js';
|
|
15
|
+
import { PublicationStatus } from '../types/publication-status.js';
|
|
16
|
+
import { ResubmissionOptions } from '../types/resubmission-options.js';
|
|
20
17
|
/**
|
|
21
18
|
* Operator-facing query + resubmit API for every publication that has
|
|
22
19
|
* not yet reached the terminal `COMPLETED` state. Equivalent to Spring
|
|
@@ -46,14 +43,14 @@ let IncompleteEventPublications = class IncompleteEventPublications {
|
|
|
46
43
|
* `PROCESSING` is owned by a worker and `RESUBMITTED` is already in
|
|
47
44
|
* the retry queue. Returns the number of rows transitioned.
|
|
48
45
|
*/
|
|
49
|
-
async resubmitIncompletePublications(options =
|
|
46
|
+
async resubmitIncompletePublications(options = ResubmissionOptions.defaults()) {
|
|
50
47
|
const incomplete = await this.repository.findIncomplete();
|
|
51
48
|
const filtered = options.filter !== null ? incomplete.filter(options.filter) : incomplete;
|
|
52
49
|
const toProcess = filtered.slice(0, options.batchSize);
|
|
53
50
|
let resubmitted = 0;
|
|
54
51
|
for (const pub of toProcess) {
|
|
55
|
-
if (pub.status ===
|
|
56
|
-
await this.repository.updateStatus(pub.id,
|
|
52
|
+
if (pub.status === PublicationStatus.FAILED || pub.status === PublicationStatus.PUBLISHED) {
|
|
53
|
+
await this.repository.updateStatus(pub.id, PublicationStatus.RESUBMITTED, {
|
|
57
54
|
lastResubmissionDate: new Date(),
|
|
58
55
|
});
|
|
59
56
|
resubmitted++;
|
|
@@ -62,10 +59,10 @@ let IncompleteEventPublications = class IncompleteEventPublications {
|
|
|
62
59
|
return resubmitted;
|
|
63
60
|
}
|
|
64
61
|
};
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
(0,
|
|
68
|
-
__param(0, (0, common_1.Inject)(event_publication_repository_1.EVENT_PUBLICATION_REPOSITORY)),
|
|
62
|
+
IncompleteEventPublications = __decorate([
|
|
63
|
+
Injectable(),
|
|
64
|
+
__param(0, Inject(EVENT_PUBLICATION_REPOSITORY)),
|
|
69
65
|
__metadata("design:paramtypes", [Object])
|
|
70
66
|
], IncompleteEventPublications);
|
|
67
|
+
export { IncompleteEventPublications };
|
|
71
68
|
//# sourceMappingURL=incomplete-event-publications.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"incomplete-event-publications.js","sourceRoot":"","sources":["../../src/api/incomplete-event-publications.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"incomplete-event-publications.js","sourceRoot":"","sources":["../../src/api/incomplete-event-publications.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEpD,OAAO,EACL,4BAA4B,GAE7B,MAAM,+CAA+C,CAAC;AAEvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAEvE;;;;;;;GAOG;AAEI,IAAM,2BAA2B,GAAjC,MAAM,2BAA2B;IAGnB;IAFnB,YAEmB,UAAsC;QAAtC,eAAU,GAAV,UAAU,CAA4B;IACtD,CAAC;IAEJ,gEAAgE;IAChE,KAAK,CAAC,OAAO;QACX,OAAO,IAAI,CAAC,UAAU,CAAC,cAAc,EAAE,CAAC;IAC1C,CAAC;IAED,2DAA2D;IAC3D,KAAK,CAAC,KAAK;QACT,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,cAAc,EAAE,CAAC;QAC1D,OAAO,UAAU,CAAC,MAAM,CAAC;IAC3B,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,8BAA8B,CAClC,UAA+B,mBAAmB,CAAC,QAAQ,EAAE;QAE7D,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,cAAc,EAAE,CAAC;QAE1D,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;QAC1F,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;QAEvD,IAAI,WAAW,GAAG,CAAC,CAAC;QACpB,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;YAC5B,IAAI,GAAG,CAAC,MAAM,KAAK,iBAAiB,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,KAAK,iBAAiB,CAAC,SAAS,EAAE,CAAC;gBAC1F,MAAM,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,EAAE,iBAAiB,CAAC,WAAW,EAAE;oBACxE,oBAAoB,EAAE,IAAI,IAAI,EAAE;iBACjC,CAAC,CAAC;gBACH,WAAW,EAAE,CAAC;YAChB,CAAC;QACH,CAAC;QAED,OAAO,WAAW,CAAC;IACrB,CAAC;CACF,CAAA;AA5CY,2BAA2B;IADvC,UAAU,EAAE;IAGR,WAAA,MAAM,CAAC,4BAA4B,CAAC,CAAA;;GAF5B,2BAA2B,CA4CvC"}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const common_1 = require("@nestjs/common");
|
|
5
|
-
const core_1 = require("@nestjs-transactional/core");
|
|
6
|
-
const token_utils_1 = require("../tokens/token-utils");
|
|
1
|
+
import { Inject } from '@nestjs/common';
|
|
2
|
+
import { DEFAULT_DATA_SOURCE_NAME } from '@nestjs-transactional/core';
|
|
3
|
+
import { getEventExternalizerToken, getEventPublicationProcessorToken, getEventPublicationRegistryToken, getEventPublicationRepositoryToken, getEventTypeRegistryToken, getExternalizationRegistryToken, getOutboxEventSerializerToken, getOutboxListenerRegistryToken, getOutboxPublisherToken, } from '../tokens/token-utils.js';
|
|
7
4
|
/**
|
|
8
5
|
* Inject decorators for the outbox-side per-dataSource components
|
|
9
6
|
* (DD-022). Each decorator below is sugar over
|
|
@@ -32,62 +29,54 @@ const token_utils_1 = require("../tokens/token-utils");
|
|
|
32
29
|
* }
|
|
33
30
|
* ```
|
|
34
31
|
*/
|
|
35
|
-
const InjectOutboxPublisher = (dataSource =
|
|
36
|
-
exports.InjectOutboxPublisher = InjectOutboxPublisher;
|
|
32
|
+
export const InjectOutboxPublisher = (dataSource = DEFAULT_DATA_SOURCE_NAME) => Inject(getOutboxPublisherToken(dataSource));
|
|
37
33
|
/**
|
|
38
34
|
* Inject the per-dataSource `EventTypeRegistry`. The registry is
|
|
39
35
|
* populated by the `OutboxModule.forFeature([...])` calls made
|
|
40
36
|
* against the same dataSource — registrations do not bleed across
|
|
41
37
|
* dataSources.
|
|
42
38
|
*/
|
|
43
|
-
const InjectEventTypeRegistry = (dataSource =
|
|
44
|
-
exports.InjectEventTypeRegistry = InjectEventTypeRegistry;
|
|
39
|
+
export const InjectEventTypeRegistry = (dataSource = DEFAULT_DATA_SOURCE_NAME) => Inject(getEventTypeRegistryToken(dataSource));
|
|
45
40
|
/**
|
|
46
41
|
* Inject the per-dataSource `EventPublicationRegistry` — the
|
|
47
42
|
* lifecycle coordinator that owns publication state transitions
|
|
48
43
|
* (`PUBLISHED` → `PROCESSING` → `COMPLETED` / `FAILED`).
|
|
49
44
|
*/
|
|
50
|
-
const InjectEventPublicationRegistry = (dataSource =
|
|
51
|
-
exports.InjectEventPublicationRegistry = InjectEventPublicationRegistry;
|
|
45
|
+
export const InjectEventPublicationRegistry = (dataSource = DEFAULT_DATA_SOURCE_NAME) => Inject(getEventPublicationRegistryToken(dataSource));
|
|
52
46
|
/**
|
|
53
47
|
* Inject the per-dataSource `EventPublicationProcessor` — the async
|
|
54
48
|
* worker that drains publications, dispatches them to listeners,
|
|
55
49
|
* and invokes the externalizer (when bound). Typically only needed
|
|
56
50
|
* by tests that drive the loop manually with `processBatch()`.
|
|
57
51
|
*/
|
|
58
|
-
const InjectEventPublicationProcessor = (dataSource =
|
|
59
|
-
exports.InjectEventPublicationProcessor = InjectEventPublicationProcessor;
|
|
52
|
+
export const InjectEventPublicationProcessor = (dataSource = DEFAULT_DATA_SOURCE_NAME) => Inject(getEventPublicationProcessorToken(dataSource));
|
|
60
53
|
/**
|
|
61
54
|
* Inject the per-dataSource `OutboxListenerRegistry` — registry of
|
|
62
55
|
* listener entries scanned from `@OutboxEventsHandler` classes (and,
|
|
63
56
|
* when wired, `@IntegrationEventsHandler` classes routed via the
|
|
64
57
|
* outbox).
|
|
65
58
|
*/
|
|
66
|
-
const InjectOutboxListenerRegistry = (dataSource =
|
|
67
|
-
exports.InjectOutboxListenerRegistry = InjectOutboxListenerRegistry;
|
|
59
|
+
export const InjectOutboxListenerRegistry = (dataSource = DEFAULT_DATA_SOURCE_NAME) => Inject(getOutboxListenerRegistryToken(dataSource));
|
|
68
60
|
/**
|
|
69
61
|
* Inject the per-dataSource `ExternalizationRegistry` — maps event
|
|
70
62
|
* type names to their `@Externalized` metadata. Consumed by the
|
|
71
63
|
* processor at dispatch time; rarely needed by application code.
|
|
72
64
|
*/
|
|
73
|
-
const InjectExternalizationRegistry = (dataSource =
|
|
74
|
-
exports.InjectExternalizationRegistry = InjectExternalizationRegistry;
|
|
65
|
+
export const InjectExternalizationRegistry = (dataSource = DEFAULT_DATA_SOURCE_NAME) => Inject(getExternalizationRegistryToken(dataSource));
|
|
75
66
|
/**
|
|
76
67
|
* Inject the per-dataSource `EventPublicationRepository`. Adapter
|
|
77
68
|
* packages (`outbox-typeorm`, future `outbox-prisma`, ...) register
|
|
78
69
|
* their concrete repository under this token. Most application
|
|
79
70
|
* code injects the higher-level `OutboxEventPublisher` instead.
|
|
80
71
|
*/
|
|
81
|
-
const InjectEventPublicationRepository = (dataSource =
|
|
82
|
-
exports.InjectEventPublicationRepository = InjectEventPublicationRepository;
|
|
72
|
+
export const InjectEventPublicationRepository = (dataSource = DEFAULT_DATA_SOURCE_NAME) => Inject(getEventPublicationRepositoryToken(dataSource));
|
|
83
73
|
/**
|
|
84
74
|
* Inject the per-dataSource `EventExternalizer`. Multi-adapter
|
|
85
75
|
* processes can wire externalization independently per outbox stack
|
|
86
76
|
* — e.g. the `'billing'` outbox emits to Kafka, the `'audit'` outbox
|
|
87
77
|
* is internal-only and binds no externalizer.
|
|
88
78
|
*/
|
|
89
|
-
const InjectEventExternalizer = (dataSource =
|
|
90
|
-
exports.InjectEventExternalizer = InjectEventExternalizer;
|
|
79
|
+
export const InjectEventExternalizer = (dataSource = DEFAULT_DATA_SOURCE_NAME) => Inject(getEventExternalizerToken(dataSource));
|
|
91
80
|
/**
|
|
92
81
|
* Inject the per-dataSource `EventSerializer` used by the outbox to
|
|
93
82
|
* marshal events into the stored JSON payload and revive them at
|
|
@@ -95,6 +84,5 @@ exports.InjectEventExternalizer = InjectEventExternalizer;
|
|
|
95
84
|
* serialization strategies (e.g. one JSON, another schema-validated)
|
|
96
85
|
* without forcing one strategy process-wide.
|
|
97
86
|
*/
|
|
98
|
-
const InjectOutboxEventSerializer = (dataSource =
|
|
99
|
-
exports.InjectOutboxEventSerializer = InjectOutboxEventSerializer;
|
|
87
|
+
export const InjectOutboxEventSerializer = (dataSource = DEFAULT_DATA_SOURCE_NAME) => Inject(getOutboxEventSerializerToken(dataSource));
|
|
100
88
|
//# sourceMappingURL=inject-decorators.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inject-decorators.js","sourceRoot":"","sources":["../../src/decorators/inject-decorators.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"inject-decorators.js","sourceRoot":"","sources":["../../src/decorators/inject-decorators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAEtE,OAAO,EACL,yBAAyB,EACzB,iCAAiC,EACjC,gCAAgC,EAChC,kCAAkC,EAClC,yBAAyB,EACzB,+BAA+B,EAC/B,6BAA6B,EAC7B,8BAA8B,EAC9B,uBAAuB,GACxB,MAAM,0BAA0B,CAAC;AAElC;;;;;;;;;;GAUG;AAEH;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,aAAqB,wBAAwB,EACzB,EAAE,CAAC,MAAM,CAAC,uBAAuB,CAAC,UAAU,CAAC,CAAC,CAAC;AAErE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CACrC,aAAqB,wBAAwB,EACzB,EAAE,CAAC,MAAM,CAAC,yBAAyB,CAAC,UAAU,CAAC,CAAC,CAAC;AAEvE;;;;GAIG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAC5C,aAAqB,wBAAwB,EACzB,EAAE,CAAC,MAAM,CAAC,gCAAgC,CAAC,UAAU,CAAC,CAAC,CAAC;AAE9E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAC7C,aAAqB,wBAAwB,EACzB,EAAE,CAAC,MAAM,CAAC,iCAAiC,CAAC,UAAU,CAAC,CAAC,CAAC;AAE/E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAC1C,aAAqB,wBAAwB,EACzB,EAAE,CAAC,MAAM,CAAC,8BAA8B,CAAC,UAAU,CAAC,CAAC,CAAC;AAE5E;;;;GAIG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAC3C,aAAqB,wBAAwB,EACzB,EAAE,CAAC,MAAM,CAAC,+BAA+B,CAAC,UAAU,CAAC,CAAC,CAAC;AAE7E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAC9C,aAAqB,wBAAwB,EACzB,EAAE,CAAC,MAAM,CAAC,kCAAkC,CAAC,UAAU,CAAC,CAAC,CAAC;AAEhF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CACrC,aAAqB,wBAAwB,EACzB,EAAE,CAAC,MAAM,CAAC,yBAAyB,CAAC,UAAU,CAAC,CAAC,CAAC;AAEvE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,CACzC,aAAqB,wBAAwB,EACzB,EAAE,CAAC,MAAM,CAAC,6BAA6B,CAAC,UAAU,CAAC,CAAC,CAAC"}
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.OUTBOX_EVENTS_HANDLER_METADATA = void 0;
|
|
4
|
-
exports.OutboxEventsHandler = OutboxEventsHandler;
|
|
5
|
-
exports.getOutboxEventsHandlerMetadata = getOutboxEventsHandlerMetadata;
|
|
6
|
-
require("reflect-metadata");
|
|
1
|
+
import 'reflect-metadata';
|
|
7
2
|
/**
|
|
8
3
|
* Metadata key under which {@link OutboxEventsHandlerMetadata} is
|
|
9
4
|
* stored on classes decorated with {@link OutboxEventsHandler}.
|
|
@@ -14,15 +9,15 @@ require("reflect-metadata");
|
|
|
14
9
|
* package uses the `OUTBOX_LISTENER_REGISTRAR` structural port, not
|
|
15
10
|
* metadata introspection, to route handlers to the outbox.
|
|
16
11
|
*/
|
|
17
|
-
|
|
18
|
-
function OutboxEventsHandler(...args) {
|
|
12
|
+
export const OUTBOX_EVENTS_HANDLER_METADATA = Symbol('OUTBOX_EVENTS_HANDLER_METADATA');
|
|
13
|
+
export function OutboxEventsHandler(...args) {
|
|
19
14
|
const metadata = resolveMetadata(args);
|
|
20
15
|
if (metadata.eventTypes.length === 0) {
|
|
21
16
|
throw new Error('@OutboxEventsHandler requires at least one event type. ' +
|
|
22
17
|
'Pass class constructors as rest arguments or via the `events` option.');
|
|
23
18
|
}
|
|
24
19
|
return (target) => {
|
|
25
|
-
Reflect.defineMetadata(
|
|
20
|
+
Reflect.defineMetadata(OUTBOX_EVENTS_HANDLER_METADATA, metadata, target);
|
|
26
21
|
};
|
|
27
22
|
}
|
|
28
23
|
function resolveMetadata(args) {
|
|
@@ -51,8 +46,8 @@ function isOptionsObject(candidate) {
|
|
|
51
46
|
* by {@link OutboxEventsHandler}. Returns `undefined` when the
|
|
52
47
|
* class was not decorated.
|
|
53
48
|
*/
|
|
54
|
-
function getOutboxEventsHandlerMetadata(target) {
|
|
55
|
-
const value = Reflect.getMetadata(
|
|
49
|
+
export function getOutboxEventsHandlerMetadata(target) {
|
|
50
|
+
const value = Reflect.getMetadata(OUTBOX_EVENTS_HANDLER_METADATA, target);
|
|
56
51
|
return value;
|
|
57
52
|
}
|
|
58
53
|
//# sourceMappingURL=outbox-events-handler.decorator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outbox-events-handler.decorator.js","sourceRoot":"","sources":["../../src/decorators/outbox-events-handler.decorator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"outbox-events-handler.decorator.js","sourceRoot":"","sources":["../../src/decorators/outbox-events-handler.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAI1B;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,MAAM,CAAC,gCAAgC,CAAC,CAAC;AAiFvF,MAAM,UAAU,mBAAmB,CACjC,GAAG,IAA2C;IAE9C,MAAM,QAAQ,GAAgC,eAAe,CAAC,IAAI,CAAC,CAAC;IAEpE,IAAI,QAAQ,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CACb,yDAAyD;YACvD,uEAAuE,CAC1E,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,MAAc,EAAQ,EAAE;QAC9B,OAAO,CAAC,cAAc,CAAC,8BAA8B,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC3E,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,IAA2C;IAClE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAClD,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACxB,OAAO;YACL,UAAU,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;YAC/B,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,IAAI;SAC/C,CAAC;IACJ,CAAC;IAED,OAAO;QACL,UAAU,EAAE,IAAc;QAC1B,cAAc,EAAE,IAAI;KACrB,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,SAAkB;IACzC,OAAO,CACL,SAAS,KAAK,IAAI;QAClB,OAAO,SAAS,KAAK,QAAQ;QAC7B,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;QACzB,OAAO,SAAS,KAAK,UAAU;QAC/B,QAAQ,IAAI,SAAS,CACtB,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,8BAA8B,CAC5C,MAAc;IAEd,MAAM,KAAK,GAAY,OAAO,CAAC,WAAW,CAAC,8BAA8B,EAAE,MAAM,CAAC,CAAC;IACnF,OAAO,KAAgD,CAAC;AAC1D,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { EventPublicationRegistry } from '../registry/event-publication-registry';
|
|
2
|
-
import type { OutboxListenerRegistry } from '../registry/listener-registry';
|
|
1
|
+
import type { EventPublicationRegistry } from '../registry/event-publication-registry.js';
|
|
2
|
+
import type { OutboxListenerRegistry } from '../registry/listener-registry.js';
|
|
3
3
|
/**
|
|
4
4
|
* Per-dataSource publisher. Owns the per-transaction
|
|
5
5
|
* buffer, lifecycle hook registration, and delegate calls into the
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.DataSourceOutboxPublisher = void 0;
|
|
4
|
-
const common_1 = require("@nestjs/common");
|
|
5
|
-
const core_1 = require("@nestjs-transactional/core");
|
|
1
|
+
import { Logger } from '@nestjs/common';
|
|
2
|
+
import { IllegalTransactionStateError, TransactionContext, } from '@nestjs-transactional/core';
|
|
6
3
|
/**
|
|
7
4
|
* Per-dataSource publisher. Owns the per-transaction
|
|
8
5
|
* buffer, lifecycle hook registration, and delegate calls into the
|
|
@@ -20,7 +17,7 @@ const core_1 = require("@nestjs-transactional/core");
|
|
|
20
17
|
* — the facade transparently delegates to the only registered
|
|
21
18
|
* `DataSourceOutboxPublisher`.
|
|
22
19
|
*/
|
|
23
|
-
class DataSourceOutboxPublisher {
|
|
20
|
+
export class DataSourceOutboxPublisher {
|
|
24
21
|
dataSource;
|
|
25
22
|
registry;
|
|
26
23
|
listenerRegistry;
|
|
@@ -41,7 +38,7 @@ class DataSourceOutboxPublisher {
|
|
|
41
38
|
this.dataSource = dataSource;
|
|
42
39
|
this.registry = registry;
|
|
43
40
|
this.listenerRegistry = listenerRegistry;
|
|
44
|
-
this.logger = new
|
|
41
|
+
this.logger = new Logger(`DataSourceOutboxPublisher[${dataSource}]`);
|
|
45
42
|
}
|
|
46
43
|
/**
|
|
47
44
|
* Publish a single event into this dataSource's outbox. Must be
|
|
@@ -88,7 +85,7 @@ class DataSourceOutboxPublisher {
|
|
|
88
85
|
* transactions in the same async stack.
|
|
89
86
|
*/
|
|
90
87
|
scheduleForPublication(event) {
|
|
91
|
-
const tx =
|
|
88
|
+
const tx = TransactionContext.getActiveTransactionByDataSource(this.dataSource);
|
|
92
89
|
if (tx === undefined) {
|
|
93
90
|
void this.publish(event).catch((err) => {
|
|
94
91
|
this.logger.error(`scheduleForPublication outside an active '${this.dataSource}' transaction failed: ${err instanceof Error ? err.message : String(err)}`, err instanceof Error ? err.stack : undefined);
|
|
@@ -113,14 +110,13 @@ class DataSourceOutboxPublisher {
|
|
|
113
110
|
buffer.push(event);
|
|
114
111
|
}
|
|
115
112
|
ensureActiveTransaction() {
|
|
116
|
-
const tx =
|
|
113
|
+
const tx = TransactionContext.getActiveTransactionByDataSource(this.dataSource);
|
|
117
114
|
if (tx === undefined) {
|
|
118
|
-
throw new
|
|
115
|
+
throw new IllegalTransactionStateError(`OutboxEventPublisher.publish for dataSource '${this.dataSource}' must be ` +
|
|
119
116
|
`called inside an active transaction for that dataSource. Wrap the call ` +
|
|
120
117
|
`in @Transactional({ dataSource: '${this.dataSource}' }) so the publication ` +
|
|
121
118
|
`row commits atomically with the business write.`);
|
|
122
119
|
}
|
|
123
120
|
}
|
|
124
121
|
}
|
|
125
|
-
exports.DataSourceOutboxPublisher = DataSourceOutboxPublisher;
|
|
126
122
|
//# sourceMappingURL=data-source-outbox-publisher.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-source-outbox-publisher.js","sourceRoot":"","sources":["../../src/dispatcher/data-source-outbox-publisher.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"data-source-outbox-publisher.js","sourceRoot":"","sources":["../../src/dispatcher/data-source-outbox-publisher.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { type EventExternalizer } from '../externalization/event-externalizer';
|
|
2
|
-
import { ExternalizationRegistry } from '../externalization/externalization-registry';
|
|
3
|
-
import { EventPublicationRegistry } from '../registry/event-publication-registry';
|
|
4
|
-
import { OutboxListenerRegistry } from '../registry/listener-registry';
|
|
5
|
-
import type { EventPublicationProcessorOptions } from './processor-options';
|
|
1
|
+
import { type EventExternalizer } from '../externalization/event-externalizer.js';
|
|
2
|
+
import { ExternalizationRegistry } from '../externalization/externalization-registry.js';
|
|
3
|
+
import { EventPublicationRegistry } from '../registry/event-publication-registry.js';
|
|
4
|
+
import { OutboxListenerRegistry } from '../registry/listener-registry.js';
|
|
5
|
+
import type { EventPublicationProcessorOptions } from './processor-options.js';
|
|
6
6
|
/**
|
|
7
7
|
* Async worker that drains the event publication queue:
|
|
8
8
|
*
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
2
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
3
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -12,15 +11,13 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
12
11
|
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
12
|
};
|
|
14
13
|
var EventPublicationProcessor_1;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const listener_registry_1 = require("../registry/listener-registry");
|
|
23
|
-
const drain_1 = require("../shutdown/drain");
|
|
14
|
+
import { Inject, Injectable, Logger, Optional } from '@nestjs/common';
|
|
15
|
+
import { ExternalizationError } from '../externalization/errors.js';
|
|
16
|
+
import { EVENT_EXTERNALIZER, } from '../externalization/event-externalizer.js';
|
|
17
|
+
import { ExternalizationRegistry } from '../externalization/externalization-registry.js';
|
|
18
|
+
import { EventPublicationRegistry } from '../registry/event-publication-registry.js';
|
|
19
|
+
import { OutboxListenerRegistry } from '../registry/listener-registry.js';
|
|
20
|
+
import { drainWithTimeout } from '../shutdown/drain.js';
|
|
24
21
|
/**
|
|
25
22
|
* Async worker that drains the event publication queue:
|
|
26
23
|
*
|
|
@@ -45,7 +42,7 @@ let EventPublicationProcessor = EventPublicationProcessor_1 = class EventPublica
|
|
|
45
42
|
options;
|
|
46
43
|
externalizer;
|
|
47
44
|
externalizationRegistry;
|
|
48
|
-
logger = new
|
|
45
|
+
logger = new Logger(EventPublicationProcessor_1.name);
|
|
49
46
|
running = false;
|
|
50
47
|
processingLoop = null;
|
|
51
48
|
/**
|
|
@@ -90,7 +87,7 @@ let EventPublicationProcessor = EventPublicationProcessor_1 = class EventPublica
|
|
|
90
87
|
}
|
|
91
88
|
const inFlight = this.inFlightBatch;
|
|
92
89
|
if (inFlight !== null) {
|
|
93
|
-
const drained = await
|
|
90
|
+
const drained = await drainWithTimeout(inFlight, this.options.shutdownTimeout);
|
|
94
91
|
if (!drained) {
|
|
95
92
|
this.logger.warn(`EventPublicationProcessor drain timed out after ${this.options.shutdownTimeout}ms — ` +
|
|
96
93
|
'the in-flight batch was abandoned. Publications left in PROCESSING ' +
|
|
@@ -206,7 +203,7 @@ let EventPublicationProcessor = EventPublicationProcessor_1 = class EventPublica
|
|
|
206
203
|
catch (err) {
|
|
207
204
|
const cause = err instanceof Error ? err : undefined;
|
|
208
205
|
const message = err instanceof Error ? err.message : String(err);
|
|
209
|
-
throw new
|
|
206
|
+
throw new ExternalizationError(`Externalization failed for ${publication.eventType}: ${message}`, publication.eventType, metadata.target, cause);
|
|
210
207
|
}
|
|
211
208
|
}
|
|
212
209
|
chunk(arr, size) {
|
|
@@ -217,13 +214,13 @@ let EventPublicationProcessor = EventPublicationProcessor_1 = class EventPublica
|
|
|
217
214
|
return chunks;
|
|
218
215
|
}
|
|
219
216
|
};
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
(
|
|
223
|
-
__param(3, (
|
|
224
|
-
__param(
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
listener_registry_1.OutboxListenerRegistry, Object, Object, externalization_registry_1.ExternalizationRegistry])
|
|
217
|
+
EventPublicationProcessor = EventPublicationProcessor_1 = __decorate([
|
|
218
|
+
Injectable(),
|
|
219
|
+
__param(3, Optional()),
|
|
220
|
+
__param(3, Inject(EVENT_EXTERNALIZER)),
|
|
221
|
+
__param(4, Optional()),
|
|
222
|
+
__metadata("design:paramtypes", [EventPublicationRegistry,
|
|
223
|
+
OutboxListenerRegistry, Object, Object, ExternalizationRegistry])
|
|
228
224
|
], EventPublicationProcessor);
|
|
225
|
+
export { EventPublicationProcessor };
|
|
229
226
|
//# sourceMappingURL=event-publication-processor.js.map
|