I stumbled upon AsyncLocalStorage and wrote some test code to play around with it.
My assumption was, that I can use it to set a state for a code chain and this state will magically exist in all code called inside of that chain without passing it explicitly as parameters. My assumption or code is wrong.
import { AsyncLocalStorage } from "async_hooks";
const als = new AsyncLocalStorage();
async function logStorePromise(prefix: string): Promise<void> {
console.log(`${prefix} ${JSON.stringify(als.getStore())}`);
await new Promise<void>(r => r());
}
als.run(
{ foo: "bar" },
async () => {
logStorePromise("start")
.then(() => logStorePromise("then"));
als.disable();
console.log("> disabled");
}
);
This logs
start {"foo":"bar"}
> disabled
end undefined
then undefined
My assuption was
start {"foo":"bar"}
> disabled
end undefined
then {"foo":"bar"}
Can someone explain to me where my misunderstanding lies?
I understand, that the then
in my Promise chain places my () => logStorePromise("then")
on the microtask queue. At the moment it is called, the Store is already disabled. Same as if I would use a global object that I clear when disabled is called.
Real use-case scenario
Let’s say I have an express server and use the AsyncLocalStorage to add a trackingId to each incoming request.
Let’s also say that request starts some asynchronous tasks and returns before they are finished.
After my test code above I would assume, that I should not clear the tracking id when the request is done as it would also remove that state from still running tasks.
But I feel like I should clear that state, because of memory and because I fear that express reuses that context somehow and the tracking id could still be set on some other call.