fastify / fastify-request-context

Request-scoped storage support, based on Asynchronous Local Storage (with fallback to cls-hooked)
MIT License
153 stars 13 forks source link

lost context when use @fastify/multipart #153

Open wvq opened 1 year ago

wvq commented 1 year ago

Prerequisites

Fastify version

4.15.0

Plugin version

4.2.0

Node.js version

18.14.0

Operating system

macOS

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

11.3

Description

when register multipart after context, the router frequently lost context info

Steps to Reproduce

const Fastify = require('fastify').default
const MultipartSupport = require('@fastify/multipart')
const { requestContext } = require('@fastify/request-context')
const RequestContextSupport = require('@fastify/request-context')

const server = Fastify({ logger: true })

server.register(RequestContextSupport, {
  defaultStoreValues: {
    user: { id: 0 },
  },
})

server.addHook('onRequest', async (req, reply) => {
  req.requestContext.set('user', { id: 1 })
})

server.register(MultipartSupport, {
  addToBody: true,
})

server.post('/', async (req, reply) => {
  console.log(req.requestContext.get('user'))

  return { message: 'ok' }
})

server.listen({ host: '0.0.0.0', port: 3002 })

use postman to send any file to http://127.0.0.1/, console.log(req.requestContext.get('user')) sometimes are undefined

Expected Behavior

No response

climba03003 commented 1 year ago

The comment from source code already explain why it happen. It is the limitation of EventEmitter async resources.

https://github.com/fastify/fastify-request-context/blob/e5a722071c104b6785eced39e23e14176f38511e/index.js#L32-L41

It would be better to point it out in the readme. Would you like to work on this?

kibertoad commented 1 year ago

@climba03003 Shouldn't the commented block help restore the correct context in that case? It was added to fix the context being lost when using body-parser, I wonder if some additional tweak is needed there to correctly handle multipart parsing hook as well.

climba03003 commented 1 year ago

Shouldn't the commented block help restore the correct context in that case?

Yes, it also explain why the parser will mess up the context because busboy also an EventEmitter.

wvq commented 1 year ago

@climba03003 @kibertoad Thanks for reply. But it still confused me, as it run on different async context, why sometimes output context correct?

kibertoad commented 1 year ago

I'll write a couple of tests, but I think that it should work correctly if you register request-context plugin after the multipart one, so that it gets a chance to rebind the context correctly

wvq commented 1 year ago

Yes, I register request-context after multipart to avoid this problem, it works fine.

In my situaction, I want:

  1. get header properties then set user info to request-context.
  2. in multipart onFile callback, store files in difference directory base on the user info
  3. process other logic in some routes also need user info (has lost context problem)

Now, Call step 2 first, means the onFile callback need resolve step 1 logic; and then call step 1 to set context, it a bad performance.

To avoid performance issue, I need to set property to req, and step 1 check if the property exists, the code is ugly.

mcollina commented 1 year ago

I think we should solve this in our multipart module by adding a AsyncResource at the right moment.

mcollina commented 1 year ago

Thanks for reporting! Would you like to send a Pull Request to address this issue? Remember to add unit tests.