Nó giải quyết bài toán truyền context xuyên qua chuỗi bất đồng bộ mà không phải thêm tham số vào mọi hàm.
Trong Node không có thread-local storage; AsyncLocalStorage là bản tương đương cho môi trường async: một store gắn với "vùng chạy" và tự theo suốt các await, callback, promise chain sinh ra từ đó.
import { AsyncLocalStorage } from 'node:async_hooks'
import { randomUUID } from 'node:crypto'
const context = new AsyncLocalStorage()
app.use((req, res, next) => {
const store = { requestId: req.headers['x-request-id'] ?? randomUUID() }
context.run(store, next)
})
export function log(message) {
const store = context.getStore()
console.log(JSON.stringify({ requestId: store?.requestId, message }))
}Hàm ở tầng sâu (repository, service) gọi log() là tự có requestId, không cần nhận thêm tham số.
Ứng dụng thường gặp: correlation id cho log, trace context của APM (OpenTelemetry dùng chính cơ chế này), thông tin user/tenant cho multi-tenant, transaction handle của DB.
Lưu ý:
- getStore() trả undefined nếu code chạy ngoài run() — vd trong setInterval khởi tạo lúc boot. Luôn xử lý trường hợp thiếu store.
- Store là một object bình thường: mutate được, nhưng đừng nhét dữ liệu lớn vào vì nó sống hết vòng đời request.
- API đã stable, nhưng nó vẫn dựa trên async_hooks nên có chi phí; đo trước khi dùng ở đường chạy siêu nóng.