JavaScript Async Contextãæ¢æ±ãããªã¯ãšã¹ãã¹ã³ãŒã倿°ã广çã«ç®¡çããŸããã°ããŒãã«ã¢ããªã±ãŒã·ã§ã³å šäœã®ããã©ãŒãã³ã¹ãšä¿å®æ§ãåäžãããŸãã
JavaScript Async ContextïŒã°ããŒãã«ã¢ããªã±ãŒã·ã§ã³ã®ããã®ãªã¯ãšã¹ãã¹ã³ãŒã倿°
é²åãç¶ãããŠã§ãéçºã®äžçã«ãããŠãå ç¢ã§ã¹ã±ãŒã©ãã«ãªã¢ããªã±ãŒã·ã§ã³ãç¹ã«ã°ããŒãã«ãªãŠãŒã¶ãŒã察象ãšããã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããã«ã¯ãéåæããã°ã©ãã³ã°ãšã³ã³ããã¹ã管çã«é¢ããæ·±ãçè§£ãæ±ããããŸãããã®ããã°èšäºã§ã¯ãJavaScript Async Contextãšããé åçãªäžçã«é£ã³èŸŒã¿ãŸããããã¯ããªã¯ãšã¹ãã¹ã³ãŒã倿°ãæ±ãããã®åŒ·åãªãã¯ããã¯ã§ãããç¹ã«ãã€ã¯ããµãŒãã¹ã忣ã·ã¹ãã ã®ã³ã³ããã¹ãã«ãããŠãã¢ããªã±ãŒã·ã§ã³ã®ããã©ãŒãã³ã¹ãä¿å®æ§ããããã°ã®ãããããå€§å¹ ã«åäžãããŸãã
課é¡ã®çè§£ïŒéåææäœãšã³ã³ããã¹ãã®åªå€±
çŸä»£ã®ãŠã§ãã¢ããªã±ãŒã·ã§ã³ã¯éåææäœã®äžã«æ§ç¯ãããŠããŸãããŠãŒã¶ãŒãªã¯ãšã¹ãã®åŠçãããããŒã¿ããŒã¹ãšã®å¯Ÿè©±ãAPIã®åŒã³åºããããã¯ã°ã©ãŠã³ãã¿ã¹ã¯ã®å®è¡ãŸã§ãJavaScriptã®éåææ§ã¯åºæ¬çãªèŠçŽ ã§ãããããããã®éåææ§ã¯é倧ãªèª²é¡ããããããŸããããã¯ã³ã³ããã¹ãã®åªå€±ã§ãããªã¯ãšã¹ããåŠçãããéããã®ãªã¯ãšã¹ãã«é¢é£ããããŒã¿ïŒäŸïŒãŠãŒã¶ãŒIDãã»ãã·ã§ã³æ å ±ããã¬ãŒã·ã³ã°çšã®çžé¢IDãªã©ïŒã¯ãè€æ°ã®éåæé¢æ°åŒã³åºãã«ãŸããã£ãŠããåŠçã©ã€ããµã€ã¯ã«å šäœãéããŠã¢ã¯ã»ã¹å¯èœã§ããå¿ èŠããããŸãã
äŸãã°ãæ±äº¬ïŒæ¥æ¬ïŒã®ãŠãŒã¶ãŒãã°ããŒãã«ãªeã³ããŒã¹ãã©ãããã©ãŒã ã«ãªã¯ãšã¹ããéä¿¡ããã·ããªãªãèããŠã¿ãŸãããããã®ãªã¯ãšã¹ãã¯ãèªèšŒãèªå¯ãããŒã¿ããŒã¹ïŒäŸãã°ã¢ã€ã«ã©ã³ãã«ããïŒããã®ããŒã¿ååŸã泚æåŠçããããŠæçµçã«ç¢ºèªã¡ãŒã«ã®éä¿¡ãšãã£ãäžé£ã®æäœãããªã¬ãŒããŸããé©åãªã³ã³ããã¹ã管çããªããã°ããŠãŒã¶ãŒã®ãã±ãŒã«ïŒé貚ãèšèªã®ãã©ãŒãããçšïŒããªã¯ãšã¹ãå ã®IPã¢ãã¬ã¹ïŒã»ãã¥ãªãã£çšïŒããããŠããããã¹ãŠã®ãµãŒãã¹ã暪æããŠãªã¯ãšã¹ãã远跡ããããã®äžæã®èå¥åã®ãããªéèŠãªæ å ±ã¯ãéåææäœãå±éãããã«ã€ããŠå€±ãããŠããŸãã§ãããã
åŸæ¥ãéçºè ã¯ã³ã³ããã¹ã倿°ã颿°ãã©ã¡ãŒã¿ãéããŠæåã§æž¡ããããã°ããŒãã«å€æ°ãå©çšããããšãã£ãåé¿çã«é Œã£ãŠããŸããããããããããã®ã¢ãããŒãã¯ãã°ãã°ç ©éã§ãšã©ãŒãçºçãããããã³ãŒããèªã¿ã«ããä¿å®ãã«ãããã®ã«ãªãå¯èœæ§ããããŸããæåã§ã®ã³ã³ããã¹ãæž¡ãã¯ãéåææäœããã¹ãããã颿°åŒã³åºãã®æ°ãå¢ããã«ã€ããŠãããã«æã«è² ããªããªããŸããäžæ¹ãã°ããŒãã«å€æ°ã¯æå³ããªãå¯äœçšãåŒãèµ·ããå¯èœæ§ããããç¹ã«ãã«ãã¹ã¬ããç°å¢ããã€ã¯ããµãŒãã¹ã«ãããŠãã¢ããªã±ãŒã·ã§ã³ã®ç¶æ ãæšè«ããããšãå°é£ã«ããŸãã
Async Contextã®ç޹ä»ïŒåŒ·åãªãœãªã¥ãŒã·ã§ã³
JavaScript Async Contextã¯ãã³ã³ããã¹ãäŒæã®åé¡ã«å¯ŸããŠãããã¯ãªãŒã³ã§ãšã¬ã¬ã³ããªãœãªã¥ãŒã·ã§ã³ãæäŸããŸããããã«ãããããŒã¿ïŒã³ã³ããã¹ãïŒãéåææäœã«é¢é£ä»ããéåæåŒã³åºãã®æ°ããã¹ãã®æ·±ãã«é¢ããããå®è¡ãã§ãŒã³å šäœãéããŠãã®ããŒã¿ãèªåçã«å©çšå¯èœã«ãªãããšãä¿èšŒããŸãããã®ã³ã³ããã¹ãã¯ãªã¯ãšã¹ãã¹ã³ãŒãã§ããããããªã¯ãšã¹ãã«é¢é£ä»ããããã³ã³ããã¹ãã¯ä»ã®ãªã¯ãšã¹ãããéé¢ããããããããŒã¿ã®æŽåæ§ã確ä¿ãããçžäºæ±æã鲿¢ãããŸãã
Async Contextã䜿çšããäž»ãªå©ç¹ïŒ
- ã³ãŒãã®å¯èªæ§ã®åäžïŒæåã§ã®ã³ã³ããã¹ãæž¡ãã®å¿ èŠæ§ãæžããããã¯ãªãŒã³ã§ç°¡æœãªã³ãŒãã«ãªããŸãã
- ä¿å®æ§ã®åŒ·åïŒã³ã³ããã¹ãããŒã¿ã®è¿œè·¡ãšç®¡çã容æã«ãªãããããã°ãšã¡ã³ããã³ã¹ãç°¡çŽ åãããŸãã
- ãšã©ãŒãã³ããªã³ã°ã®ç°¡çŽ åïŒãšã©ãŒå ±åæã«ã³ã³ããã¹ãæ å ±ãžã®ã¢ã¯ã»ã¹ãæäŸããããšã§ãäžå çãªãšã©ãŒãã³ããªã³ã°ãå¯èœã«ãªããŸãã
- ããã©ãŒãã³ã¹ã®åäžïŒå¿ èŠãªæã«é©åãªã³ã³ããã¹ãããŒã¿ãå©çšå¯èœã«ãªãããšãä¿èšŒãããªãœãŒã¹å©çšãæé©åããŸãã
- ã»ãã¥ãªãã£ã®åŒ·åïŒãŠãŒã¶ãŒIDãèªèšŒããŒã¯ã³ãªã©ã®æ©å¯æ å ±ããã¹ãŠã®éåæåŒã³åºãã«ããã£ãŠå®¹æã«è¿œè·¡ããããšã§ãå®å šãªæäœãä¿é²ããŸãã
Node.jsïŒããã³ãã以éïŒã§ã®Async Contextã®å®è£
JavaScriptèšèªèªäœã«ã¯çµã¿èŸŒã¿ã®Async Contextæ©èœã¯ãããŸããããç¹ã«Node.jsç°å¢ã§ã¯ããã®æ©èœãæäŸããããã®ããã€ãã®ã©ã€ãã©ãªããã¯ããã¯ãç»å ŽããŠããŸããããã€ãã®äžè¬çãªã¢ãããŒããæ¢ã£ãŠã¿ãŸãããïŒ
1. `async_hooks` ã¢ãžã¥ãŒã«ïŒNode.jsã³ã¢ïŒ
Node.jsã¯ãéåæãªãœãŒã¹ããã¬ãŒã¹ããããã®äœã¬ãã«APIãæäŸãã`async_hooks`ãšããçµã¿èŸŒã¿ã¢ãžã¥ãŒã«ãæäŸããŠããŸããããã«ãããéåææäœã®ã©ã€ãã¿ã€ã ã远跡ããäœæãå®è¡åãå®è¡åŸãªã©ã®ããŸããŸãªã€ãã³ãã«ããã¯ããããšãã§ããŸãã匷åã§ã¯ãããŸããã`async_hooks`ã¢ãžã¥ãŒã«ã¯ã³ã³ããã¹ãäŒæãå®è£ ããããã«ããå€ãã®æäœæ¥ãå¿ èŠãšããéåžžã¯ããé«ã¬ãã«ãªã©ã€ãã©ãªã®ãã«ãã£ã³ã°ãããã¯ãšããŠäœ¿çšãããŸãã
const async_hooks = require('async_hooks');
const context = new Map();
let executionAsyncId = 0;
const init = (asyncId, type, triggerAsyncId, resource) => {
context.set(asyncId, {}); // Initialize a context object for each async operation
};
const before = (asyncId) => {
executionAsyncId = asyncId;
};
const after = (asyncId) => {
executionAsyncId = 0; // Clear the current execution asyncId
};
const destroy = (asyncId) => {
context.delete(asyncId); // Remove context when the async operation completes
};
const asyncHook = async_hooks.createHook({
init,
before,
after,
destroy,
});
asyncHook.enable();
function getContext() {
return context.get(executionAsyncId) || {};
}
function setContext(data) {
const currentContext = getContext();
context.set(executionAsyncId, { ...currentContext, ...data });
}
async function doSomethingAsync() {
const contextData = getContext();
console.log('Inside doSomethingAsync context:', contextData);
// ... asynchronous operation ...
}
async function main() {
// Simulate a request
const requestId = Math.random().toString(36).substring(2, 15);
setContext({ requestId });
console.log('Outside doSomethingAsync context:', getContext());
await doSomethingAsync();
}
main();
説æïŒ
- `async_hooks.createHook()`ïŒéåæãªãœãŒã¹ã®ã©ã€ããµã€ã¯ã«ã€ãã³ããã€ã³ã¿ãŒã»ããããããã¯ãäœæããŸãã
- `init`ïŒæ°ããéåæãªãœãŒã¹ãäœæããããšãã«åŒã³åºãããŸããããã䜿çšããŠããªãœãŒã¹ã®ã³ã³ããã¹ããªããžã§ã¯ããåæåããŸãã
- `before`ïŒéåæãªãœãŒã¹ã®ã³ãŒã«ããã¯ãå®è¡ãããçŽåã«åŒã³åºãããŸããããã䜿çšããŠãå®è¡ã³ã³ããã¹ããæŽæ°ããŸãã
- `after`ïŒã³ãŒã«ããã¯ãå®è¡ãããåŸã«åŒã³åºãããŸãã
- `destroy`ïŒéåæãªãœãŒã¹ãç Žæ£ããããšãã«åŒã³åºãããŸããé¢é£ããã³ã³ããã¹ããåé€ããŸãã
- `getContext()` ãš `setContext()`ïŒã³ã³ããã¹ãã¹ãã¢ãžã®èªã¿æžããè¡ããã«ããŒé¢æ°ã§ãã
ãã®äŸã¯äžå¿çãªååã瀺ããŠããŸãããå°çšã®ã©ã€ãã©ãªã䜿çšããæ¹ããå€ãã®å Žåãããç°¡åã§ä¿å®ãããããªããŸãã
2. `cls-hooked` ãŸã㯠`continuation-local-storage` ã©ã€ãã©ãªã®äœ¿çš
ããå¹ççãªã¢ãããŒããšããŠã`cls-hooked`ïŒãŸãã¯ãã®å身ã§ããã`cls-hooked`ãåºã¥ããŠãã`continuation-local-storage`ïŒã®ãããªã©ã€ãã©ãªã¯ã`async_hooks`ãããé«ã¬ãã«ã§æœè±¡åãããã®ãæäŸããŸãããããã®ã©ã€ãã©ãªã¯ãã³ã³ããã¹ãã®äœæãšç®¡çã®ããã»ã¹ãç°¡çŽ åããŸããéåžžãã³ã³ããã¹ãããŒã¿ãä¿æããããã«ãã¹ãã¢ãïŒå€ãã®å Žå`Map`ãåæ§ã®ããŒã¿æ§é ïŒã䜿çšããéåææäœéã§ã³ã³ããã¹ããèªåçã«äŒæãããŸãã
const { AsyncLocalStorage } = require('node:async_hooks');
const asyncLocalStorage = new AsyncLocalStorage();
function middleware(req, res, next) {
const requestId = Math.random().toString(36).substring(2, 15);
asyncLocalStorage.run({ requestId }, () => {
// The rest of the request handling logic...
console.log('Middleware Context:', asyncLocalStorage.getStore());
next();
});
}
async function doSomethingAsync() {
const store = asyncLocalStorage.getStore();
console.log('Inside doSomethingAsync:', store);
// ... asynchronous operation ...
}
async function routeHandler(req, res) {
console.log('Route Handler Context:', asyncLocalStorage.getStore());
await doSomethingAsync();
res.send('Request processed');
}
// Simulate a request
const request = { /*...*/ };
const response = { send: (message) => console.log('Response:', message) };
middleware(request, response, () => {
routeHandler(request, response);
});
説æïŒ
- `AsyncLocalStorage`ïŒNode.jsã®ãã®ã³ã¢ã¯ã©ã¹ã¯ãéåæã³ã³ããã¹ãã管çããããã®ã€ã³ã¹ã¿ã³ã¹ãäœæããããã«äœ¿çšãããŸãã
- `asyncLocalStorage.run(context, callback)`ïŒãã®ã¡ãœããã¯ãæäŸãããã³ãŒã«ããã¯é¢æ°ã«ã³ã³ããã¹ããèšå®ããããã«äœ¿çšãããŸããã³ãŒã«ããã¯å ã§å®è¡ããããã¹ãŠã®éåææäœã«ã³ã³ããã¹ããèªåçã«äŒæããŸãã
- `asyncLocalStorage.getStore()`ïŒãã®ã¡ãœããã¯ãéåææäœå ã§çŸåšã®ã³ã³ããã¹ãã«ã¢ã¯ã»ã¹ããããã«äœ¿çšãããŸãã`asyncLocalStorage.run()`ã«ãã£ãŠèšå®ãããã³ã³ããã¹ããååŸããŸãã
`AsyncLocalStorage`ã䜿çšãããšãã³ã³ããã¹ã管çãç°¡çŽ åãããŸããéåæã®å¢çãè¶ããŠã³ã³ããã¹ãããŒã¿ãèªåçã«äŒæããããããå®åçãªã³ãŒããåæžãããŸãã
3. ãã¬ãŒã ã¯ãŒã¯ã«ãããã³ã³ããã¹ãäŒæ
NestJSãExpressãKoaãªã©ã®å€ãã®çŸä»£çãªãŠã§ããã¬ãŒã ã¯ãŒã¯ã¯ãã¢ããªã±ãŒã·ã§ã³æ§é å ã§Async Contextãå®è£ ããããã®çµã¿èŸŒã¿ãµããŒããæšå¥šãã¿ãŒã³ãæäŸããŠããŸãããããã®ãã¬ãŒã ã¯ãŒã¯ã¯ããã°ãã°`cls-hooked`ã®ãããªã©ã€ãã©ãªãšçµ±åããããç¬èªã®ã³ã³ããã¹ã管çã¡ã«ããºã ãæäŸãããããŸãããã¬ãŒã ã¯ãŒã¯ã®éžæãããªã¯ãšã¹ãã¹ã³ãŒã倿°ãæ±ãæãé©åãªæ¹æ³ã決å®ããããšãå€ãã§ããããã®æ ¹æ¬çãªååã¯åãã§ãã
äŸãã°ãNestJSã§ã¯ã`REQUEST`ã¹ã³ãŒããš`AsyncLocalStorage`ã¢ãžã¥ãŒã«ã掻çšããŠãªã¯ãšã¹ãã³ã³ããã¹ãã管çã§ããŸããããã«ããããµãŒãã¹ãã³ã³ãããŒã©å ã§ãªã¯ãšã¹ãåºæã®ããŒã¿ã«ã¢ã¯ã»ã¹ã§ããèªèšŒããã®ã³ã°ããã®ä»ã®ãªã¯ãšã¹ãé¢é£æäœã®åŠçã容æã«ãªããŸãã
å®è·µçãªäŸãšãŠãŒã¹ã±ãŒã¹
ã°ããŒãã«ã¢ããªã±ãŒã·ã§ã³ã«ãããããã€ãã®å®è·µçãªã·ããªãªã§ãAsync Contextãã©ã®ããã«é©çšã§ããããæ¢ã£ãŠã¿ãŸãããïŒ
1. ãã®ã³ã°ãšãã¬ãŒã·ã³ã°
ç°ãªãå°åã«å±éããããã€ã¯ããµãŒãã¹ãæã€åæ£ã·ã¹ãã ãæ³åããŠã¿ãŠãã ããïŒäŸïŒã¢ãžã¢ã®ãŠãŒã¶ãŒåãã«ã·ã³ã¬ããŒã«ã®ãµãŒãã¹ãåç±³ã®ãŠãŒã¶ãŒåãã«ãã©ãžã«ã®ãµãŒãã¹ããšãŒãããã®ãŠãŒã¶ãŒåãã«ãã€ãã®ãµãŒãã¹ïŒãåãµãŒãã¹ã¯å šäœã®ãªã¯ãšã¹ãåŠçã®äžéšãæ ããŸããAsync Contextã䜿çšãããšãã·ã¹ãã ãééããåãªã¯ãšã¹ãã«å¯ŸããŠäžæã®çžé¢IDãç°¡åã«çæããäŒæãããããšãã§ããŸãããã®IDããã°ã¹ããŒãã¡ã³ãã«è¿œå ããããšã§ãå°ççãªå¢çãè¶ããŠããè€æ°ã®ãµãŒãã¹ã«ãŸããããªã¯ãšã¹ãã®è¡çšã远跡ããããšãã§ããŸãã
// Pseudo-code example (Illustrative)
const correlationId = generateCorrelationId();
asyncLocalStorage.run({ correlationId }, async () => {
// Service 1
log('Service 1: Request received', { correlationId });
await callService2();
});
async function callService2() {
// Service 2
log('Service 2: Processing request', { correlationId: asyncLocalStorage.getStore().correlationId });
// ... Call a database, etc.
}
ãã®ã¢ãããŒãã«ãããããŸããŸãªå°ççãã±ãŒã·ã§ã³ã«ãŸãããã¢ããªã±ãŒã·ã§ã³ã®å¹ççãã€å¹æçãªãããã°ãããã©ãŒãã³ã¹åæãã¢ãã¿ãªã³ã°ãå¯èœã«ãªããŸããç°ãªããã®ã³ã°ãã©ãããã©ãŒã ïŒäŸïŒELK StackãSplunkïŒéã§ã®è§£æãã¯ãšãªã容æã«ããããã«ãæ§é åãã®ã³ã°ïŒäŸïŒJSON圢åŒïŒã®äœ¿çšãæ€èšããŠãã ããã
2. èªèšŒãšèªå¯
ã°ããŒãã«ãªeã³ããŒã¹ãã©ãããã©ãŒã ã§ã¯ãããŸããŸãªåœã®ãŠãŒã¶ãŒãç°ãªãæš©éã¬ãã«ãæã£ãŠãããããããŸãããAsync Contextã䜿çšããŠããŠãŒã¶ãŒèªèšŒæ å ±ïŒäŸïŒãŠãŒã¶ãŒIDãããŒã«ãæš©éïŒãã³ã³ããã¹ãå ã«ä¿åã§ããŸãããã®æ å ±ã¯ããªã¯ãšã¹ãã®ã©ã€ããµã€ã¯ã«äžãã¢ããªã±ãŒã·ã§ã³ã®ãã¹ãŠã®éšåã§å®¹æã«å©çšå¯èœã«ãªããŸãããã®ã¢ãããŒãã«ããã颿°åŒã³åºããéããŠãŠãŒã¶ãŒèªèšŒæ å ±ãç¹°ãè¿ãæž¡ããããåããŠãŒã¶ãŒã«å¯ŸããŠè€æ°åã®ããŒã¿ããŒã¹ã¯ãšãªãå®è¡ãããããå¿ èŠããªããªããŸãããã®ã¢ãããŒãã¯ããã©ãããã©ãŒã ãæ¥æ¬ããªãŒã¹ãã©ãªã¢ãã«ãããªã©ãããŸããŸãªåœã®IDãããã€ããŒãšã®ã·ã³ã°ã«ãµã€ã³ãªã³ïŒSSOïŒããµããŒãããŠããå Žåã«ç¹ã«åœ¹ç«ã¡ãäžçäžã®ãŠãŒã¶ãŒã«ã·ãŒã ã¬ã¹ã§å®å šãªäœéšãä¿èšŒããŸãã
// Pseudo-code
// Middleware
async function authenticateUser(req, res, next) {
const user = await authenticate(req.headers.authorization); // Assume auth logic
asyncLocalStorage.run({ user }, () => {
next();
});
}
// Inside a route handler
function getUserData() {
const user = asyncLocalStorage.getStore().user;
// Access user information, e.g., user.roles, user.country, etc.
}
3. ããŒã«ã©ã€ãŒãŒã·ã§ã³ãšåœéåïŒi18nïŒ
ã°ããŒãã«ã¢ããªã±ãŒã·ã§ã³ã¯ãèšèªãéè²šãæ¥æåœ¢åŒãªã©ããŠãŒã¶ãŒã®å¥œã¿ã«é©å¿ããå¿ èŠããããŸããAsync ContextãæŽ»çšããããšã§ããã±ãŒã«ããã®ä»ã®ãŠãŒã¶ãŒèšå®ãã³ã³ããã¹ãå ã«ä¿åã§ããŸãããã®ããŒã¿ã¯ã¢ããªã±ãŒã·ã§ã³ã®ãã¹ãŠã®ã³ã³ããŒãã³ãã«èªåçã«äŒæããããŠãŒã¶ãŒã®å Žæãåªå èšèªã«åºã¥ããŠãåçãªã³ã³ãã³ãã¬ã³ããªã³ã°ãé貚æç®ãæ¥æãã©ãŒããããå¯èœã«ãªããŸããããã«ãããäŸãã°ã¢ã«ãŒã³ãã³ãããããã ãŸã§ãåœéçãªã³ãã¥ããã£åãã®ã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããããšã容æã«ãªããŸãã
// Pseudo-code
// Middleware
async function setLocale(req, res, next) {
const userLocale = req.headers['accept-language'] || 'en-US';
asyncLocalStorage.run({ locale: userLocale }, () => {
next();
});
}
// Inside a component
function formatPrice(price, currency) {
const locale = asyncLocalStorage.getStore().locale;
// Use a localization library (e.g., Intl) to format the price
const formattedPrice = new Intl.NumberFormat(locale, { style: 'currency', currency }).format(price);
return formattedPrice;
}
4. ãšã©ãŒãã³ããªã³ã°ãšã¬ããŒã
è€éã§ã°ããŒãã«ã«åæ£ããã¢ããªã±ãŒã·ã§ã³ã§ãšã©ãŒãçºçããå Žåãåé¡ãè¿ éã«èšºæã解決ããããã«ååãªã³ã³ããã¹ãããã£ããã£ããããšãéèŠã§ããAsync Contextã䜿çšããããšã§ããŠãŒã¶ãŒIDãçžé¢IDããããã¯ãŠãŒã¶ãŒã®å Žæãªã©ããªã¯ãšã¹ãåºæã®æ å ±ã§ãšã©ãŒãã°ãå å®ãããããšãã§ããŸããããã«ããããšã©ãŒã®æ ¹æ¬åå ãç¹å®ãã圱é¿ãåããŠããç¹å®ã®ãªã¯ãšã¹ããçªãæ¢ããã®ã容æã«ãªããŸããã¢ããªã±ãŒã·ã§ã³ãã·ã³ã¬ããŒã«ã«æ ç¹ãçœ®ãæ±ºæžã²ãŒããŠã§ã€ããªãŒã¹ãã©ãªã¢ã®ã¯ã©ãŠãã¹ãã¬ãŒãžãªã©ãããŸããŸãªãµãŒãããŒãã£ãµãŒãã¹ãå©çšããŠããå Žåããããã®ã³ã³ããã¹ã詳现ã¯ãã©ãã«ã·ã¥ãŒãã£ã³ã°ã®éã«éåžžã«è²Žéãªãã®ãšãªããŸãã
// Pseudo-code
try {
// ... some operation ...
} catch (error) {
const contextData = asyncLocalStorage.getStore();
logError(error, { ...contextData }); // Include context information in the error log
// ... handle the error ...
}
ãã¹ããã©ã¯ãã£ã¹ãšèæ ®äºé
Async Contextã¯å€ãã®å©ç¹ãæäŸããŸããããã®å¹æçã§ä¿å®å¯èœãªå®è£ ãä¿èšŒããããã«ã¯ããã¹ããã©ã¯ãã£ã¹ã«åŸãããšãäžå¯æ¬ ã§ãïŒ
- å°çšã©ã€ãã©ãªã®äœ¿çšïŒ`cls-hooked`ã®ãããªã©ã€ãã©ãªããã¬ãŒã ã¯ãŒã¯åºæã®ã³ã³ããã¹ãç®¡çæ©èœã掻çšããŠãã³ã³ããã¹ãäŒæãç°¡çŽ åããå¹çåããŸãã
- ã¡ã¢ãªäœ¿çšéã«æ³šæããïŒå€§ããªã³ã³ããã¹ããªããžã§ã¯ãã¯ã¡ã¢ãªãæ¶è²»ããå¯èœæ§ããããŸããçŸåšã®ãªã¯ãšã¹ãã«å¿ èŠãªããŒã¿ã®ã¿ãä¿åããŠãã ããã
- ãªã¯ãšã¹ãã®æåŸã«ã³ã³ããã¹ããã¯ãªã¢ããïŒãªã¯ãšã¹ããå®äºããåŸãã³ã³ããã¹ããé©åã«ã¯ãªã¢ãããããšã確èªããŠãã ãããããã«ãããã³ã³ããã¹ãããŒã¿ãåŸç¶ã®ãªã¯ãšã¹ãã«æŒæŽ©ããã®ãé²ããŸãã
- ãšã©ãŒãã³ããªã³ã°ãèæ ®ããïŒæªåŠçã®äŸå€ãã³ã³ããã¹ãäŒæã劚ããªãããã«ãå ç¢ãªãšã©ãŒãã³ããªã³ã°ãå®è£ ããŠãã ããã
- 培åºçã«ãã¹ãããïŒãã¹ãŠã®éåææäœããã³ãã¹ãŠã®ã·ããªãªã§ã³ã³ããã¹ãããŒã¿ãæ£ããäŒæãããããšãæ€èšŒããããã«ãå æ¬çãªãã¹ããäœæããŠãã ãããã°ããŒãã«ãªã¿ã€ã ãŸãŒã³ããŸãããŠãŒã¶ãŒã§ã®ãã¹ãïŒäŸïŒãã³ãã³ãå京ããã¥ãŒãšãŒã¯ã®ãŠãŒã¶ãŒãš1æ¥ã®ç°ãªãæé垯ã§ãã¹ãããïŒãæ€èšããŠãã ããã
- ããã¥ã¡ã³ããŒã·ã§ã³ïŒéçºè ãã³ã³ããã¹ãç®¡çæŠç¥ãçè§£ãã广çã«äœæ¥ã§ããããã«ãæç¢ºã«ææžåããŠãã ããããã®ããã¥ã¡ã³ãã¯ã³ãŒãããŒã¹ã®ä»ã®éšåãšäžç·ã«å«ããŠãã ããã
- é床ã®äœ¿çšãé¿ããïŒAsync Contextã¯æ éã«äœ¿çšããŠãã ãããæ¢ã«é¢æ°ãã©ã¡ãŒã¿ãšããŠå©çšå¯èœãªããŒã¿ããçŸåšã®ãªã¯ãšã¹ãã«é¢é£ã®ãªãããŒã¿ãã³ã³ããã¹ãã«ä¿åããªãã§ãã ããã
- ããã©ãŒãã³ã¹ã«é¢ããèæ ®äºé ïŒAsync Contextèªäœã¯éåžžãé倧ãªããã©ãŒãã³ã¹ãªãŒããŒãããããããããŸããããã³ã³ããã¹ãå ã®ããŒã¿ã䜿çšããŠå®è¡ããæäœãããã©ãŒãã³ã¹ã«åœ±é¿ãäžããå¯èœæ§ããããŸããããŒã¿ã¢ã¯ã»ã¹ãæé©åããäžèŠãªèšç®ãæå°éã«æããŠãã ããã
- ã»ãã¥ãªãã£ã«é¢ããèæ ®äºé ïŒæ©å¯ããŒã¿ïŒäŸïŒãã¹ã¯ãŒãïŒãçŽæ¥ã³ã³ããã¹ãã«ä¿åããªãã§ãã ãããã³ã³ããã¹ãã§äœ¿çšããŠããæ å ±ãé©åã«åŠçã»ä¿è·ããåžžã«ã»ãã¥ãªãã£ã®ãã¹ããã©ã¯ãã£ã¹ãéµå®ããŠãã ããã
çµè«ïŒã°ããŒãã«ã¢ããªã±ãŒã·ã§ã³éçºã®åŒ·å
JavaScript Async Contextã¯ãçŸä»£ã®ãŠã§ãã¢ããªã±ãŒã·ã§ã³ã§ãªã¯ãšã¹ãã¹ã³ãŒã倿°ã管çããããã®åŒ·åã§ãšã¬ã¬ã³ããªãœãªã¥ãŒã·ã§ã³ãæäŸããŸãããã®ãã¯ããã¯ãåãå ¥ããããšã§ãéçºè ã¯ãç¹ã«ã°ããŒãã«ãªãªãŒãã£ãšã³ã¹ã察象ãšãããããå ç¢ã§ä¿å®æ§ãé«ããããã©ãŒãã³ã¹ã®è¯ãã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ã§ããŸãããã®ã³ã°ããã¬ãŒã·ã³ã°ã®å¹çåãããèªèšŒãããŒã«ã©ã€ãŒãŒã·ã§ã³ã®ä¿é²ãŸã§ãAsync Contextã¯ãåœéçãªãŠãŒã¶ãŒã®ããã«çã«ã¹ã±ãŒã©ãã«ã§äœ¿ããããã¢ããªã±ãŒã·ã§ã³ãäœæããã°ããŒãã«ãªãŠãŒã¶ãŒãšããžãã¹ã«ããžãã£ããªåœ±é¿ãäžããããã®æ°å€ãã®å©ç¹ãè§£ãæŸã¡ãŸãã
ååãçè§£ããé©åãªããŒã«ïŒ`async_hooks`ã`cls-hooked`ã®ãããªã©ã€ãã©ãªãªã©ïŒãéžæãããã¹ããã©ã¯ãã£ã¹ã«åŸãããšã§ãAsync Contextã®åãæŽ»çšããŠéçºã¯ãŒã¯ãããŒãåäžããã倿§ã§ã°ããŒãã«ãªãŠãŒã¶ãŒããŒã¹ã«åè¶ãããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãåµé ããããšãã§ããŸãããã€ã¯ããµãŒãã¹ã¢ãŒããã¯ãã£ãå€§èŠæš¡ãªeã³ããŒã¹ãã©ãããã©ãŒã ããŸãã¯ã·ã³ãã«ãªAPIãæ§ç¯ããŠãããã©ããã«ããããããAsync Contextãçè§£ã广çã«å©çšããããšã¯ã仿¥ã®æ¥éã«é²åãããŠã§ãéçºã®äžçã§æåããããã«äžå¯æ¬ ã§ãã