Feature Proposal - async variables (like thread local storage from C)

# Guy Margalit (6 years ago)

Hey

It's my first attempt to contribute to ECMAScript so would love your feedback if I better off change how I go about it.

The problem I want to highlight is that besides argument passing it is impossible to have any information associated with a flow of async code as any async code will create its own context and will only get the arguments passed to it from its caller.

A simple use case for information that is not easy to pass as arguments is "transaction ID" where unique IDs are generated at the beginning of a transaction, and propagate that ID to any function that is being called as part of that transaction.

However as a javascript codebase grows, it becomes hard to introduce new project-wide information such as transaction ID when the only mechanism to pass such information is function argument passing, and this becomes impossible as many times you are using other libraries of code inside the code stack, and one cannot change all the code just to add arguments.

Few examples:

  • Identify HTTP requests and print that a request ID in every log print that was fan-out from that request.
  • Find how many database calls one async flow created.
  • Keep pools of resources (buffers / connections / tokens) per request.

In C/C++ one can use thread local storage (en.wikipedia.org wiki/Thread-local_storage) to keep information that automatically switches with the threads context switch.

I imagine a similar mechanism, in the spirit of javascript - define a variable as async:

async var name = <initial value>;

Async variables will be saved and restored automatically when the context is resumed. It should probably have a more precise definition in ECMAScript terms.

async var reqid = '';

http_server.on('request', handler);

async function handler(req, res) => {

  // setting async variable concurrently be different requests
  // will retain the generated value for the other calls made by this
context (sync or async).
  reqid = `REQ-${uuid()}`;

  await load_data_from_db(req);
  await send_analytics_info(req);
  send_reply(res);
});

async function load_data_from_db(req) {
  console.log(`${reqid} load_data_from_db`);
  try {
     ...
  } catch (err) {
    ...
    if (err.code === 'ACCESS_DENIED') {
      console.log(`${reqid} ACCESS_DENIED. this incident will be reported.
`);
    }
  }
}

async function send_analytics_info(req) {
  console.log(`${reqid} send_analytics_info`);
  ...
  analytics.send(reqid, ...);
  ...
}

function send_reply(res) {
  console.log(`${reqid} send_analytics_info`);
  ...
  res.setHeader('reqid', reqid); // for supportability
  res.send(...);
  ...
}

Technically speaking, async variables should be replaced whenever there is a context switch - either when a sync stack returns to the top stack level, or when an async function returns from await.

However, this means that every registration of a function for later, such as setTimeout(func), should also keep the async variables which sounds difficult.

Would be great to hear if you think this is valuable and feasible, or maybe there's a way to design this with less overhead.

Thanks, Guy Margalit

# Thomas Grainger (6 years ago)

I'm pretty sure this is Zones

# Guy Margalit (6 years ago)

Yes, it is. Thanks for referring me to the right point. Anything I can do to help advance that proposal?

On Mar 11, 2018 5:40 PM, "Thomas Grainger" <tagrain at gmail.com> wrote:

I'm pretty sure this is Zones