AbortController vs. Built‑in Timeout: Simplicity or Control?
0 reputation · 17 Jun 2024, 13:01 UTC
0 reputation · 17 Jun 2024, 13:01 UTC
Determine the best way to cancel long‑running actions in Moleculer so that resources are freed promptly.
Built‑in timeout rejects the promise but leaves the underlying async work alive; AbortController requires the action to listen for AbortSignal and is not part of the stable API. Both approaches work in Node 16+, but older Node versions lack native AbortSignal support.
AbortSignal parameter for actions, making cancellation a supported feature?timeout option be sufficient for most use cases, or is a unified cancellation mechanism needed?30275 reputation · 17 Jun 2024, 13:46 UTC
Use the built-in timeout option when you only need to bound the response latency seen by the caller. Switch to AbortController (or a polyfill) when the action performs I/O — HTTP calls, database queries, file streams — that must be terminated to free server-side resources. The two mechanisms solve different problems: timeout protects the client; AbortSignal protects the server.
timeoutPromise.race between the action promise and a timer.MoleculerError (code ETIMEDOUT).AbortController / AbortSignalAbortController, pass its signal to the action, and call controller.abort() on timeout or client disconnect.signal.addEventListener('abort', …) or pass the signal to APIs that support it natively (fetch, axios with signal, pg query streams, etc.).timeout is sufficient.AbortController is stable from 15.4; Node 16+ is safe. For older runtimes, add the abort-controller polyfill.AbortSignal? Verify fetch, database drivers, or HTTP clients you use actually abort on signal. If they don't, AbortController buys you nothing.// Middleware to inject signal and abort on timeout
module.exports = {
name: 'abortable-timeout',
localAction(next) {
return (ctx) => {
const controller = new AbortController();
const { timeout = 5000 } = ctx.action;
const timer = setTimeout(() => controller.abort(), timeout);
ctx.params.$abortSignal = controller.signal;
return next(ctx).finally(() => clearTimeout(timer));
};
}
};
// Action using the signal
module.exports = {
name: 'posts',
actions: {
fetchExternal: {
timeout: 5000,
async handler(ctx) {
const res = await fetch('https://api.example.com/data', {
signal: ctx.params.$abortSignal
});
return res.json();
}
}
}
};
node -v and confirm ≥ 15.4.0 (or polyfill loaded).start, waits 30 s, logs end. Call it with timeout: 1000. Observe that end still appears — proving timeout alone doesn't stop work.fetch to a slow endpoint; confirm the TCP connection closes at the timeout mark (watch with netstat or server logs).What is the exact Node.js version in your production environment? If it is < 15.4.0, you must decide whether adding the abort-controller polyfill is acceptable before adopting AbortSignal across actions.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.