@nextage/era-lib 1.0.209 → 1.0.210
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.
|
@@ -13,6 +13,8 @@ export declare abstract class MsgListener<T extends Event> extends Listener<T> {
|
|
|
13
13
|
private subscription;
|
|
14
14
|
private messageStack;
|
|
15
15
|
private wait;
|
|
16
|
+
/** The id of the envelope being handled, so a failure can name the event it belongs to. */
|
|
17
|
+
private inFlightId;
|
|
16
18
|
protected ackWait: number;
|
|
17
19
|
constructor(provider: ClientProvider);
|
|
18
20
|
protected transportNameForLog(): string;
|
|
@@ -40,6 +42,30 @@ export declare abstract class MsgListener<T extends Event> extends Listener<T> {
|
|
|
40
42
|
* previous event.
|
|
41
43
|
*/
|
|
42
44
|
protected handleMessage(msg: Message): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Standardized "message failed" log - the ONE place a HANDLED in-memory failure is reported.
|
|
47
|
+
*
|
|
48
|
+
* ⚠ THIS IS THE OBSERVABILITY CONTRACT OF THIS TRANSPORT, not a consolation prize. The bus is
|
|
49
|
+
* best-effort by design: there is no ack to withhold, no nak to send and no redelivery to
|
|
50
|
+
* schedule, so a failure that has been handled leaves a log line and nothing else. Whatever
|
|
51
|
+
* must survive an error belongs on `NatsListener`, which owns the durable vocabulary.
|
|
52
|
+
*
|
|
53
|
+
* ⚠ IT LIVES HERE AND NOT ON `Listener`. The failure semantics it describes is the in-memory
|
|
54
|
+
* one; `NatsListener` reports its own failures beside its nak/DLQ decisions and would never
|
|
55
|
+
* call this. Giving the shared base an API only one transport uses would be uniformity for its
|
|
56
|
+
* own sake.
|
|
57
|
+
*
|
|
58
|
+
* `protected` on purpose, and no wider: a multi-item subclass has to report the failure of ONE
|
|
59
|
+
* element and carry on with the others, and that is the only reason this is not private.
|
|
60
|
+
*
|
|
61
|
+
* @param error what went wrong
|
|
62
|
+
* @param data the event - or the ITEM of a cascade, when the caller can name it
|
|
63
|
+
* @param method the logical method, for the structured context
|
|
64
|
+
*/
|
|
65
|
+
protected logFailure(error: unknown, data?: {
|
|
66
|
+
id?: string;
|
|
67
|
+
code?: string;
|
|
68
|
+
}, method?: string): void;
|
|
43
69
|
/**
|
|
44
70
|
* Unsubscribes from the in-memory bus on shutdown.
|
|
45
71
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-msg-listener.d.ts","sourceRoot":"","sources":["../../../src/events/base/base-msg-listener.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAyD,kBAAkB,CAAC;AAE9F,OAAO,EAAE,cAAc,EAAE,KAAK,EAAsB,eAAe,EAAE,MAAM,eAAe,CAAC;AAC3F,OAAO,EAAE,QAAQ,EAAE,MAAwD,iBAAiB,CAAC;AAG7F;;;;;GAKG;AACH,8BAAsB,WAAW,CAAC,CAAC,SAAS,KAAK,CAAE,SAAQ,QAAQ,CAAC,CAAC,CAAC;IAEpE,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAEhE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiB;IAC1C,OAAO,CAAC,YAAY,CAAqC;IAEzD,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,IAAI,CAAiC;IAE7C,SAAS,CAAC,OAAO,EAAU,MAAM,CAAe;gBAEnC,QAAQ,EAAE,cAAc;cAMlB,mBAAmB,IAAI,MAAM;IAOhD,OAAO,KAAK,MAAM,GAGjB;IAED;;;;;OAKG;IACH,mBAAmB,IAAI,eAAe;IAKhC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"base-msg-listener.d.ts","sourceRoot":"","sources":["../../../src/events/base/base-msg-listener.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAyD,kBAAkB,CAAC;AAE9F,OAAO,EAAE,cAAc,EAAE,KAAK,EAAsB,eAAe,EAAE,MAAM,eAAe,CAAC;AAC3F,OAAO,EAAE,QAAQ,EAAE,MAAwD,iBAAiB,CAAC;AAG7F;;;;;GAKG;AACH,8BAAsB,WAAW,CAAC,CAAC,SAAS,KAAK,CAAE,SAAQ,QAAQ,CAAC,CAAC,CAAC;IAEpE,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAEhE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiB;IAC1C,OAAO,CAAC,YAAY,CAAqC;IAEzD,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,IAAI,CAAiC;IAE7C,2FAA2F;IAC3F,OAAO,CAAC,UAAU,CAA4B;IAE9C,SAAS,CAAC,OAAO,EAAU,MAAM,CAAe;gBAEnC,QAAQ,EAAE,cAAc;cAMlB,mBAAmB,IAAI,MAAM;IAOhD,OAAO,KAAK,MAAM,GAGjB;IAED;;;;;OAKG;IACH,mBAAmB,IAAI,eAAe;IAKhC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB7B;;;;;OAKG;IACG,aAAa;IAqCnB;;;;;;OAMG;cACa,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IA4B1D;;;;;;;;;;;;;;;;;;;OAmBG;IACH,SAAS,CAAC,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,GAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAO,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAkBtG;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAM3B;;;;;OAKG;IACH,OAAO,CAAC,YAAY;CAKrB"}
|
|
@@ -40,7 +40,10 @@ class MsgListener extends base_listener_1.Listener {
|
|
|
40
40
|
this.subscription?.on('message', (msg) => {
|
|
41
41
|
nx_frame_be_1.APP.logger.info(`📥 Received message on: ${this.subject} / ${this.queueGroupName}`, (0, nx_frame_be_1.logClassCtx)(this));
|
|
42
42
|
this.messageStack.push(msg);
|
|
43
|
-
|
|
43
|
+
// THE PROMISE IS NEVER DROPPED. `checkMessages` handles the failure of a single message
|
|
44
|
+
// itself, so this guard should never fire - which is exactly why it is here: nothing this
|
|
45
|
+
// class starts may end up as an unhandled rejection, whatever is added below later.
|
|
46
|
+
void this.checkMessages().catch(error => this.logFailure(error));
|
|
44
47
|
});
|
|
45
48
|
}
|
|
46
49
|
/**
|
|
@@ -59,9 +62,23 @@ class MsgListener extends base_listener_1.Listener {
|
|
|
59
62
|
try {
|
|
60
63
|
await this.handleMessage(msg);
|
|
61
64
|
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
// HANDLED HERE, AND HANDLED MEANS EXACTLY THIS: the failure is reported and the message is
|
|
67
|
+
// dropped. There is no ack to withhold, no nak to send and no redelivery to schedule - the
|
|
68
|
+
// transport is best-effort by design, and a retry here would make it a different one.
|
|
69
|
+
//
|
|
70
|
+
// ⚠ WHY IT MATTERS THAT IT IS CAUGHT AT ALL. Left to propagate, this rejection escaped a
|
|
71
|
+
// promise nobody awaited and reached the process, where `nx-frame-be` installs a handler
|
|
72
|
+
// that treats an unhandled rejection as fatal and asks for an emergency shutdown. A failing
|
|
73
|
+
// subscriber must not be able to take the service down.
|
|
74
|
+
this.logFailure(error, { id: this.inFlightId });
|
|
75
|
+
}
|
|
62
76
|
finally {
|
|
63
77
|
this.wait = false;
|
|
64
78
|
}
|
|
79
|
+
// ⚠ ALWAYS REACHED, and that is the second half of the fix. When the await above threw, this
|
|
80
|
+
// line was skipped and every message already queued behind the failing one stayed in the
|
|
81
|
+
// stack until some later publish happened to restart the drain.
|
|
65
82
|
await this.checkMessages();
|
|
66
83
|
}
|
|
67
84
|
/**
|
|
@@ -72,8 +89,10 @@ class MsgListener extends base_listener_1.Listener {
|
|
|
72
89
|
* previous event.
|
|
73
90
|
*/
|
|
74
91
|
async handleMessage(msg) {
|
|
92
|
+
this.inFlightId = undefined;
|
|
75
93
|
try {
|
|
76
94
|
const { id, data, meta } = (0, cascade_1.unwrapEnvelope)(this.parseMessage(msg));
|
|
95
|
+
this.inFlightId = id;
|
|
77
96
|
const violation = (0, cascade_1.cascadeViolation)(meta, this.subject);
|
|
78
97
|
if (violation) {
|
|
79
98
|
nx_frame_be_1.APP.logger.warn(`🔁 Cascade guard tripped on '${this.subject}': ${violation}`, (0, nx_frame_be_1.logClassCtx)(this));
|
|
@@ -87,6 +106,38 @@ class MsgListener extends base_listener_1.Listener {
|
|
|
87
106
|
this._incoming = undefined;
|
|
88
107
|
}
|
|
89
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Standardized "message failed" log - the ONE place a HANDLED in-memory failure is reported.
|
|
111
|
+
*
|
|
112
|
+
* ⚠ THIS IS THE OBSERVABILITY CONTRACT OF THIS TRANSPORT, not a consolation prize. The bus is
|
|
113
|
+
* best-effort by design: there is no ack to withhold, no nak to send and no redelivery to
|
|
114
|
+
* schedule, so a failure that has been handled leaves a log line and nothing else. Whatever
|
|
115
|
+
* must survive an error belongs on `NatsListener`, which owns the durable vocabulary.
|
|
116
|
+
*
|
|
117
|
+
* ⚠ IT LIVES HERE AND NOT ON `Listener`. The failure semantics it describes is the in-memory
|
|
118
|
+
* one; `NatsListener` reports its own failures beside its nak/DLQ decisions and would never
|
|
119
|
+
* call this. Giving the shared base an API only one transport uses would be uniformity for its
|
|
120
|
+
* own sake.
|
|
121
|
+
*
|
|
122
|
+
* `protected` on purpose, and no wider: a multi-item subclass has to report the failure of ONE
|
|
123
|
+
* element and carry on with the others, and that is the only reason this is not private.
|
|
124
|
+
*
|
|
125
|
+
* @param error what went wrong
|
|
126
|
+
* @param data the event - or the ITEM of a cascade, when the caller can name it
|
|
127
|
+
* @param method the logical method, for the structured context
|
|
128
|
+
*/
|
|
129
|
+
logFailure(error, data = {}, method) {
|
|
130
|
+
const stream = this.streamNameForLog();
|
|
131
|
+
nx_frame_be_1.APP.logger.error(`${this.transportNameForLog()} ${this.subject} ${this.queueGroupName}${stream ? ` ${stream}` : ''} - FAILED ${data?.id ?? '?'} ${data?.code ?? ''}`.trimEnd(), this.loggerCtx(method, {
|
|
132
|
+
event: 'failed',
|
|
133
|
+
eventId: data?.id,
|
|
134
|
+
eventCode: data?.code,
|
|
135
|
+
eventSubject: this.subject,
|
|
136
|
+
queueGroupName: this.queueGroupName,
|
|
137
|
+
streamName: stream,
|
|
138
|
+
error
|
|
139
|
+
}));
|
|
140
|
+
}
|
|
90
141
|
/**
|
|
91
142
|
* Unsubscribes from the in-memory bus on shutdown.
|
|
92
143
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-msg-listener.js","sourceRoot":"","sources":["../../../src/events/base/base-msg-listener.ts"],"names":[],"mappings":";;;AAAA,sDAAkG;AAIlG,mDAA6F;AAC7F,wCAAwF;AAExF;;;;;GAKG;AACH,MAAsB,WAA6B,SAAQ,wBAAW;
|
|
1
|
+
{"version":3,"file":"base-msg-listener.js","sourceRoot":"","sources":["../../../src/events/base/base-msg-listener.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextage/era-lib",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.210",
|
|
4
4
|
"main": "./build/index.js",
|
|
5
5
|
"types": "./build/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"ws": "^8.18.0"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@nextage/nx-frame-be": "^1.0.
|
|
55
|
+
"@nextage/nx-frame-be": "^1.0.52",
|
|
56
56
|
"del-cli": "^6.0.0",
|
|
57
57
|
"mongodb-memory-server": "^10.1.4",
|
|
58
58
|
"vitest": "^4.1.10"
|