TypeScript icon, indicating that this package has built-in type declarations

1.1.0 • Public • Published


CI CodeQL version

fastify-racing is a plugin which allows you handle possible client request abortions by exposing an AbortSignal instance that will be aborted just and only when the client has closed the request abruptly (e.g. by closing the browser tab).

How it works?

On every request and after a first invocation, the plugin well schedule event listeners to the close event triggered by the Socket instance attached to the request object.

Along with that, the plugin will instanciate and cache an AbortController instance for each request.

When the close event is triggered, the plugin will check if the AbortSignal instance is already aborted, and if not will abort it using the AbortController instance.

Is guaranteed that one and just one AbortController and AbortSignal will be made per request.

If the request was not aborted during its lifetime, the plugin will remove the AbortController and AbortSignal from the cache. This by scheduling a hook-handler on the hook onResponse.

If the request aborted, the same hook will be used for cleaning resources.

A WeakMap is used under the hood for caching, ensuring that the AbortController and AbortSignal instances can be unlinked if not needed anymore, and for instance GC'ed.


Install by running npm install fastify-racing.

Then register the plugin to your fastify instance:

const fastify = require('fastify')({
  logger: true

fastify.register(require('fastify-racing'), {
    handleError: true,


On Setup

  • handleError: Indicates to the pluging if an event listener to the Socket error event should be attached or not. Default true.

  • onRequestClosed: Default callback to be used of none is passed during runtime It will receive as argument the event object similar to the abort event handler. Default null

How to use it?

There are two ways to use this plugin:


It will return a promise that will be resolved when the request is aborted. It will be resolved with the result of the abort event object of the AbortSignal instance. This only if no cb has been passed as argument.

It supports an object as argument:

  • opts.handleError: [Optional] Indicates to the plugin to ignore or listen to the Socket error event. Default to pluginOption.handleError passed when registering the pluging or false.


app.get('/', async (req, _reply) => {
    const signal = req.race()
    const result = await Promise.race([signal, asyncOp(signal)])

    if (result.type === 'aborted') return ''
    else return `${result}-world`

TypeScript'/', (request: FastifyRequest, reply: FastifyReply) => {
    const signal = req.race()
    const result: AbortEvent | unknown = await Promise.race([signal, asyncOp(signal)])

    if ((<AbortEvent>result).type === 'aborted') return ''
    else return `${result}-world`


If a callback is provided, no promise will be scheduled/returned during the lifetime of the request.

  • cb: Similar signature as onRequestClosed. Default undefined or to onRequestClosed if passed when registering the plugin.


app.get('/', (req, reply) => {
    const signal = req.race((evt) => {
        const result = result.type === 'aborted' ? '' : `${result}-world`


TypeScript'/', (request: FastifyRequest, reply: FastifyReply) => {
    const signal = req.race((evt: AbortEvent) => {

Type Definitions

interface AbortEvent {
    type: 'abort' | string;
    reason?: FastifyError | Error

interface FastifyRacing {
  handleError?: boolean;
  onRequestClosed?: (evt: AbortEvent) => void;

interface FastifyInstance {
    race(cb: FastifyRacing['onRequestClosed']): void
    race(opts: Omit<FastifyRacing, 'onRequestClosed'>): Promise<AbortEvent>
    race(): Promise<AbortEvent>

See test for more examples.


npm i fastify-racing

DownloadsWeekly Downloads






Unpacked Size

28.4 kB

Total Files


Last publish


  • metcoder95