Give the held-message flow one place a reader can follow it
Mirror / push (push) Successful in 6s
Test / lint (pull_request) Successful in 24s
Test / test (18) (pull_request) Successful in 32s
Test / test (20) (pull_request) Successful in 31s
Test / test (24) (pull_request) Successful in 32s
Test / test (22) (pull_request) Successful in 32s
Test / test (26) (pull_request) Successful in 31s

This commit is contained in:
2026-09-28 10:48:38 +02:00
parent 1aadcbe3c9
commit e52baafd29
3 changed files with 31 additions and 18 deletions
+28 -1
View File
@@ -25,7 +25,10 @@ type HoldEntry = {
release: () => void;
};
/** One message offered to the application, held until it is answered or every listener gives up. */
/**
* One message offered to the application. A drain waits on it until the first of: `answered()`,
* every listener that took it rejecting, no listener taking it, its deadline, or the link going.
*/
export class MessageHold {
private readonly entry: HoldEntry;
private working: number;
@@ -64,6 +67,8 @@ export class HeldMessages {
private readonly idleWaiters = new IdleWaiters();
private readonly log: SmppLog;
private readonly maxOctets: number;
/** A rejecting listener hands the message back as an `unknown`, so its hold is found by identity. */
private readonly offered = new WeakMap<object, MessageHold>();
constructor(options: HeldMessagesOptions) {
this.held = new ExpiringGroups({
@@ -112,6 +117,28 @@ export class HeldMessages {
return hold;
}
/** Holds a message, builds what the application is handed, and emits it. */
offer<T extends object>(
pduObjs: PduObject[],
listeners: number,
build: (hold: MessageHold) => T,
emit: (message: T) => boolean,
): void {
const hold = this.hold(pduObjs, listeners);
const message = build(hold);
this.offered.set(message, hold);
if (!emit(message)) hold.release();
}
/** One listener gave up on a message; the last one to do so is what releases it. */
listenerRejected(message: unknown): void {
if (typeof message !== 'object' || message === null) return;
this.offered.get(message)?.listenerGaveUp();
}
private has(pduObjs: PduObject[]): boolean {
const key = keyOf(pduObjs);