Skip to content

onSend hook can be called twice #4959

@MetalMichael

Description

@MetalMichael

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Fastify version

4.15.0

Plugin version

No response

Node.js version

16.14.0

Operating system

macOS

Operating system version (i.e. 20.04, 11.3, 10)

Ventura 13.4

Description

When using reply.send() from an async handler, with an asynchronous onSend hook, it is possible that the hook can be called more than once per request.

Fastify still uses reply.request.raw.aborted in wrapThenable, which is not reliable since NodeJS v15.5.0: nodejs/node#41117

The comments in the code state that:

the request may be terminated during the reply. in this situation, it require an extra checking of request.aborted to see whether the request is killed by client.

However, since this flag is no longer reliable, the code will call reply.send twice, which will also trigger the onSend hook more than once.

Steps to Reproduce

import fastify from "fastify";

const sleep = (ms) => {
  return new Promise((resolve) => setTimeout(resolve, ms));
};

const app = fastify({
  logger: true,
  disableRequestLogging: true,
});

app.decorateRequest('hasCalledHook', false);
app.addHook("onSend", async (request, reply) => {

  await sleep(100);
  if (request.hasCalledHook) {
    request.log.error('Called hook twice!');
  } else {
    request.hasCalledHook = true;
  }
});

app.post("/", async (request, reply) => {
  await sleep(100);
  await reply.send('test');
});

const start = async () => {
  try {
    await app.listen({ port: 3000 });
  } catch (error) {
    app.log.error(error);
    process.exit(1);
  }
};

start();

Then call from autocannon and abort the request.
E.g.
autocannon -m POST -c 1 -d 0.1 http://localhost:3000/ -b {} -H Content-Type=application/json

Expected Behavior

The onSend hook should only be called a maximum of one time per request

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugConfirmed bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions