Skip to content

Node.js server integration - isolated context per request #708

@shalvah

Description

@shalvah

Like #688, but for traditional single-threaded, server-side Node.js apps. The goal is to ensure that context does not "spill over" across concurrent requests being handled by the same process.

Problem

First, a simple proof of concept (tested with the included express example):

let i = 0;

app.get("/", (req, res) => {
  let reqId = ++i;
  console.log(`Starting request number ${reqId}, current context: ${JSON.stringify(Honeybadger.__context)}`);
  Honeybadger.setContext({ reqId });
  setTimeout(() => {
    console.log(`Ending request number ${reqId}, current context: ${JSON.stringify(Honeybadger.__context)}`);
    res.send("Done")
  }, 1000);
});

Then make two concurrent requests (I use autocannon):

autocannon --connections 2 --amount 2 http://localhost:3000

Terminal logs:

Example app listening at http://localhost:3000
Starting request number 1, current context: {"user_id":"1"}
Starting request number 2, current context: {"user_id":"1","reqId":1}
Ending request number 1, current context: {"user_id":"1","reqId":2}
Ending request number 2, current context: {"user_id":"1","reqId":2}

You can see the problem—the context is shared globally.

Fix

AsyncLocalStorage

Thankfully, @subzero10 has already implemented the stores in his recent PR to start this off.

To Do:

  • Add a test that shows this
  • Verify Node.js versions supported for this. If we're still tied to older versions, we may be able to use a polyfill like ALS' predecessor, continuation-local storage (although it doesn't seem to still be maintained), or just leave it as-is.

cc @subzero10 @joshuap

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions