Skip to content

AsyncLocalStorage not working on Nodejs 13.11.0 #32330

@averri

Description

@averri

What steps will reproduce the bug?

Please refer the following code to reproduce the issue.

package.json:

{
  "name": "async-local-storage-demo",
  "version": "1.0.0",
  "dependencies": {
    "@feathersjs/express": "^4.5.2",
    "@feathersjs/feathers": "^4.5.2",
    "@feathersjs/socketio": "^4.5.2",
    "@feathersjs/socketio-client": "^4.5.2",
    "socket.io-client": "^2.3.0"
  }
}

server.js:

const feathers = require('@feathersjs/feathers')
const express = require('@feathersjs/express')
const socketio = require('@feathersjs/socketio')
const {AsyncLocalStorage} = require('async_hooks')

const storageKey = '_logData'
const storage = new AsyncLocalStorage()

// Logs to console, adding extra information from async local storage.
const info = (...args) => {
  const store = storage.getStore()
  const context = store ? store.get(storageKey) : {status: '<undefined store>'}
  console.info(`${new Date().toISOString()}`, {...context}, ...args)
}


class MessageService {
  async find() {
    info('Invoking find') // This should log additional data from the client.
    return 'Hello from the server'
  }
}

// Creates an ExpressJS compatible Feathers application
const server = express(feathers())

// Parse HTTP JSON bodies
server.use(express.json())
// Parse URL-encoded params
server.use(express.urlencoded({extended: true}))
// Host static files from the current folder
server.use(express.static(__dirname))
// Add REST API support
server.configure(express.rest())

// Configure Socket.io real-time APIs
server.configure(socketio(io => {
  // https://docs.feathersjs.com/api/socketio.html#params
  io.use((socket, next) => {
    // Get the user agent from the request.
    const userAgent = socket.conn.request.headers['user-agent']
    // Make information available to async local storage (for logging).
    storage.run(new Map(), () => {
      storage.getStore().set(storageKey, {userAgent})
      next()
    })
  })
}))


// Register a messages service
server.use('/messages', new MessageService())
// Register a nicer error handler than the default Express one
server.use(express.errorHandler())


// Start the server
server.listen(3030).on('listening', () =>
  console.log('Feathers server listening on localhost:3030')
)

client.js:

const feathers = require('@feathersjs/feathers')
const socketio = require('@feathersjs/socketio-client')
const io = require('socket.io-client')

const debug = text => console.debug(`${new Date().toISOString()}: ${text}`)

// https://socket.io/docs/client-api/
function getAPI(url) {

  const api = feathers()

  const socket = io(url, {
    transports: ['websocket'], // Connect using websocket only.
    path: '/socket.io',
    extraHeaders: {
      'user-agent': 'Feathersjs client'
    }
  })

  api.configure(socketio(socket))

  socket.on('disconnect', () => {
    debug('Disconnected')
  })

  socket.on('reconnecting', n => {
    debug(`Reconnecting (${n})...`)
  })

  socket.on('reconnect', n =>  {
    debug(`Reconnected after ${n} tries`)
  })

  socket.on('connect', () => {
    debug('Connected')
  })

  return api
}

const api = getAPI('http://localhost:3030')

// Invoke the service 'messages' and print the response.
// This will trigger the scenario showing the issue with AsyncLocalStorage.
api.service('messages').find({}).then(console.info)

Run the server:

node server.js

Run the client:

node client.js

How often does it reproduce? Is there a required condition?

Always.

What is the expected behavior?

When the client.js starts the server.js log should print the information retrieved from AsyncLocalStorage API:

2020-03-17T18:25:13.367Z {userAgent: 'Feathersjs client' } Invoking find

What do you see instead?

The AsyncLocalStorage API return an undefined store:

2020-03-17T18:25:13.367Z { status: '<undefined store>' } Invoking find

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions