Release a message's hold when the response goes out, or when its listener failed
This commit is contained in:
@@ -39,6 +39,8 @@ export class IncomingRequests {
|
||||
private readonly session: Session;
|
||||
private readonly smsIdFormat: SmsIdFormat;
|
||||
private readonly systemId: string;
|
||||
/** Identity, not a type guard: the rejected event carries the Sms back as an `unknown`. */
|
||||
private readonly emitted = new WeakMap<object, () => void>();
|
||||
private linkGeneration = 0;
|
||||
|
||||
constructor(options: IncomingRequestsOptions) {
|
||||
@@ -111,6 +113,13 @@ export class IncomingRequests {
|
||||
this.reassembler.clear();
|
||||
}
|
||||
|
||||
/** A listener that rejected answered nothing and never will, so a shutdown may not wait for it. */
|
||||
listenerRejected(sms: unknown): void {
|
||||
if (typeof sms !== 'object' || sms === null) return;
|
||||
|
||||
this.emitted.get(sms)?.();
|
||||
}
|
||||
|
||||
/** Waits out the messages the application still holds, and says how many it never answered. */
|
||||
async drain(timeout: number, signal: AbortSignal | undefined): Promise<VoidResult> {
|
||||
const unanswered = await this.held.idle(timeout, signal);
|
||||
@@ -191,6 +200,7 @@ export class IncomingRequests {
|
||||
});
|
||||
|
||||
this.held.hold(pduObjs);
|
||||
this.emitted.set(sms, () => { this.held.release(pduObjs); });
|
||||
|
||||
// A message nobody took is not work a shutdown can wait for.
|
||||
if (!this.session.emit('sms', sms)) this.held.release(pduObjs);
|
||||
|
||||
+3
-1
@@ -93,11 +93,13 @@ export class Session extends EventEmitter<SessionEvents> {
|
||||
reason: unknown,
|
||||
...args: [event: keyof SessionEvents, ...rest: unknown[]]
|
||||
): void {
|
||||
const [event] = args;
|
||||
const [event, ...rest] = args;
|
||||
const error = errorFrom(reason);
|
||||
|
||||
this.log.error('session - a listener rejected', { event, message: error.message });
|
||||
|
||||
if (event === 'sms') this.incoming.listenerRejected(rest[0]);
|
||||
|
||||
if (event !== 'sessionError') this.emit('sessionError', error);
|
||||
}
|
||||
|
||||
|
||||
+6
-4
@@ -77,8 +77,7 @@ export function createSms(input: SmsInput, handlers: SmsHandlers): Sms {
|
||||
message: input.message,
|
||||
pduObjs: input.pduObjs,
|
||||
sendDlr: status => sendDlr(sms, handlers.send, status),
|
||||
sendResp: options => sendResp(sms, answered, options ?? {}, handlers.lostLink)
|
||||
.finally(handlers.onAnswered),
|
||||
sendResp: options => sendResp(sms, answered, options ?? {}, handlers),
|
||||
session: input.session,
|
||||
get smsId(): string {
|
||||
return answered.smsId;
|
||||
@@ -94,7 +93,7 @@ async function sendResp(
|
||||
sms: Sms,
|
||||
answered: { smsId: string },
|
||||
options: SendRespOptions,
|
||||
lostLink: () => boolean,
|
||||
handlers: SmsHandlers,
|
||||
): Promise<VoidResult> {
|
||||
const total = sms.pduObjs.length;
|
||||
|
||||
@@ -109,7 +108,7 @@ async function sendResp(
|
||||
if (options.smsId !== undefined) answered.smsId = options.smsId;
|
||||
|
||||
// A response carries the sequence number it was asked on, which the next link knows nothing about.
|
||||
if (lostLink()) {
|
||||
if (handlers.lostLink()) {
|
||||
return { err: new Error('The link this message arrived on is gone, so nothing would correlate the response') };
|
||||
}
|
||||
|
||||
@@ -119,6 +118,9 @@ async function sendResp(
|
||||
{ message_id: segmentId(answered.smsId, index, total) },
|
||||
)));
|
||||
|
||||
// Only here: a refusal above put nothing on the wire, so the peer is still owed its response.
|
||||
handlers.onAnswered();
|
||||
|
||||
return results.find(result => result.err) ?? {};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user