JavaScriptã®éåæã³ã³ããã¹ããæ¢æ±ããå ç¢ã§ã¹ã±ãŒã©ãã«ãªã¢ããªã±ãŒã·ã§ã³ã®ããã®ãªã¯ãšã¹ãã¹ã³ãŒã倿°ç®¡çæè¡ã«çŠç¹ãåœãŠãŸããAsyncLocalStorageãšãã®å¿çšã«ã€ããŠåŠã³ãŸãããã
JavaScriptã®éåæã³ã³ããã¹ãïŒãªã¯ãšã¹ãã¹ã³ãŒã倿°ç®¡çã®ç¿åŸ
éåæããã°ã©ãã³ã°ã¯ãç¹ã«Node.jsã®ãããªç°å¢ã«ãããŠãçŸä»£ã®JavaScriptéçºã®åºç€ã§ããããããéåææäœããŸããã§ã³ã³ããã¹ãããªã¯ãšã¹ãã¹ã³ãŒã倿°ã管çããããšã¯å°é£ãªå ŽåããããŸããåŸæ¥ã®ã¢ãããŒãã§ã¯ãã³ãŒããè€éã«ãªããããŒã¿ç Žæã®å¯èœæ§ãçããããšããããããŸããããã®èšäºã§ã¯ãJavaScriptã®éåæã³ã³ããã¹ãæ©èœãç¹ã«AsyncLocalStorageã«çŠç¹ãåœãŠãå
ç¢ã§ã¹ã±ãŒã©ãã«ãªã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããããã«ãªã¯ãšã¹ãã¹ã³ãŒã倿°ç®¡çãã©ã®ããã«ç°¡çŽ åããããæ¢ããŸãã
éåæã³ã³ããã¹ãã®èª²é¡ãçè§£ãã
åæããã°ã©ãã³ã°ã§ã¯ã颿°ã¹ã³ãŒãå ã®å€æ°ã管çããã®ã¯ç°¡åã§ããå颿°ã¯ç¬èªã®å®è¡ã³ã³ããã¹ããæã¡ããã®ã³ã³ããã¹ãå ã§å®£èšããã倿°ã¯åé¢ãããŠããŸããããããéåææäœã¯çŽç·çã«å®è¡ãããªããããè€éããçããŸããã³ãŒã«ããã¯ãPromiseãasync/awaitã¯æ°ããå®è¡ã³ã³ããã¹ããå°å ¥ããç¹å®ã®ãªã¯ãšã¹ããæäœã«é¢é£ãã倿°ãç¶æã»ã¢ã¯ã»ã¹ããããšãé£ãããªãå¯èœæ§ããããŸãã
ãªã¯ãšã¹ããã³ãã©ã®å®è¡å šäœãéããŠãäžæã®ãªã¯ãšã¹ãIDã远跡ããå¿ èŠãããã·ããªãªãèããŠã¿ãŸããããé©åãªã¡ã«ããºã ããªããã°ããªã¯ãšã¹ãã®åŠçã«é¢ãããã¹ãŠã®é¢æ°ã«ãªã¯ãšã¹ãIDãåŒæ°ãšããŠæž¡ããšããææ®µã«é ŒããããããŸããããã®ã¢ãããŒãã¯é¢åã§ããšã©ãŒãçºçãããããã³ãŒããå¯çµåã«ããŠããŸããŸãã
ã³ã³ããã¹ãäŒæã®åé¡
- ã³ãŒãã®æ£ä¹±ïŒè€æ°ã®é¢æ°åŒã³åºããéããŠã³ã³ããã¹ã倿°ãæž¡ããšãã³ãŒãã®è€éããå€§å¹ ã«å¢ããå¯èªæ§ãäœäžããŸãã
- å¯çµåïŒé¢æ°ãç¹å®ã®ã³ã³ããã¹ã倿°ã«äŸåããããã«ãªããåå©çšæ§ãäœãããã¹ããå°é£ã«ãªããŸãã
- ãšã©ãŒã®èµ·ãããããïŒã³ã³ããã¹ã倿°ã®æž¡ãå¿ããã誀ã£ãå€ãæž¡ãããšã¯ãäºæž¬äžèœãªæ¯ãèãããããã°ãå°é£ãªåé¡ã«ã€ãªããå¯èœæ§ããããŸãã
- ã¡ã³ããã³ã¹ã®ãªãŒããŒãããïŒã³ã³ããã¹ã倿°ã®å€æŽã¯ãã³ãŒãããŒã¹ã®è€æ°ã®éšåã«ãããä¿®æ£ãå¿ èŠãšããŸãã
ãããã®èª²é¡ã¯ãéåæJavaScriptç°å¢ã§ãªã¯ãšã¹ãã¹ã³ãŒã倿°ã管çããããã®ããããšã¬ã¬ã³ãã§å ç¢ãªãœãªã¥ãŒã·ã§ã³ã®å¿ èŠæ§ãæµ®ã圫ãã«ããŸãã
AsyncLocalStorageã®å°å ¥ïŒéåæã³ã³ããã¹ãã®è§£æ±ºç
Node.js v14.5.0ã§å°å
¥ãããAsyncLocalStorageã¯ãéåææäœã®ã©ã€ãã¿ã€ã å
šäœã§ããŒã¿ãä¿åããã¡ã«ããºã ãæäŸããŸããããã¯æ¬è³ªçã«ãéåæã®å¢çãè¶ããŠæ°žç¶çãªã³ã³ããã¹ããäœæããç¹å®ã®ãªã¯ãšã¹ããæäœã«åºæã®å€æ°ãæç€ºçã«åŒãæž¡ãããšãªãã¢ã¯ã»ã¹ã»å€æŽã§ããããã«ããŸãã
AsyncLocalStorageã¯ãå®è¡ã³ã³ããã¹ãããšã«åäœããŸããåéåææäœïŒäŸïŒãªã¯ãšã¹ããã³ãã©ïŒã¯ãããããç¬ç«ããã¹ãã¬ãŒãžãæã¡ãŸããããã«ããããããªã¯ãšã¹ãã«é¢é£ä»ããããããŒã¿ã誀ã£ãŠå¥ã®ãªã¯ãšã¹ãã«æŒããããšããªããªããããŒã¿ã®æŽåæ§ãšåé¢ãç¶æãããŸãã
AsyncLocalStorageã®ä»çµã¿
AsyncLocalStorageã¯ã©ã¹ã¯ã以äžã®äž»èŠãªã¡ãœãããæäŸããŸãïŒ
getStore()ïŒçŸåšã®å®è¡ã³ã³ããã¹ãã«é¢é£ä»ããããçŸåšã®ã¹ãã¢ãè¿ããŸããã¹ãã¢ãååšããªãå Žåã¯undefinedãè¿ããŸããrun(store, callback, ...args)ïŒæäŸãããcallbackãæ°ããéåæã³ã³ããã¹ãå ã§å®è¡ããŸããstoreåŒæ°ã¯ãã³ã³ããã¹ãã®ã¹ãã¬ãŒãžãåæåããŸããã³ãŒã«ããã¯ã«ãã£ãŠããªã¬ãŒããããã¹ãŠã®éåææäœã¯ããã®ã¹ãã¢ã«ã¢ã¯ã»ã¹ã§ããŸããenterWith(store)ïŒæäŸãããstoreã®ã³ã³ããã¹ãã«å ¥ããŸããããã¯ãç¹å®ã®ã³ãŒããããã¯ã«å¯ŸããŠæç€ºçã«ã³ã³ããã¹ããèšå®ããå¿ èŠãããå Žåã«äŸ¿å©ã§ããdisable()ïŒAsyncLocalStorageã€ã³ã¹ã¿ã³ã¹ãç¡å¹ã«ããŸããç¡å¹ã«ããåŸã«ã¹ãã¢ã«ã¢ã¯ã»ã¹ãããšãšã©ãŒã«ãªããŸãã
ã¹ãã¢èªäœã¯ã管çãããã³ã³ããã¹ã倿°ãä¿æããåçŽãªJavaScriptãªããžã§ã¯ãïŒãŸãã¯éžæããä»»æã®ããŒã¿åïŒã§ãããªã¯ãšã¹ãIDããŠãŒã¶ãŒæ å ±ããŸãã¯çŸåšã®æäœã«é¢é£ãããã®ä»ã®ããŒã¿ãä¿åã§ããŸãã
AsyncLocalStorageã®å®éã®äœ¿çšäŸ
AsyncLocalStorageã®äœ¿çšæ³ããããã€ãã®å®è·µçãªäŸã§ç€ºããŸãããã
äŸ1ïŒWebãµãŒããŒã§ã®ãªã¯ãšã¹ãIDã®è¿œè·¡
Express.jsã䜿çšããŠããNode.jsã®WebãµãŒããŒãèããŠã¿ãŸããããåä¿¡ããåãªã¯ãšã¹ãã«å¯ŸããŠäžæã®ãªã¯ãšã¹ãIDãèªåçã«çæãã远跡ããããšããŸãããã®IDã¯ããã®ã³ã°ããã¬ãŒã·ã³ã°ããããã°ã«äœ¿çšã§ããŸãã
const express = require('express');
const { AsyncLocalStorage } = require('async_hooks');
const { v4: uuidv4 } = require('uuid');
const app = express();
const asyncLocalStorage = new AsyncLocalStorage();
app.use((req, res, next) => {
const requestId = uuidv4();
asyncLocalStorage.run(new Map(), () => {
asyncLocalStorage.getStore().set('requestId', requestId);
console.log(`Request received with ID: ${requestId}`);
next();
});
});
app.get('/', (req, res) => {
const requestId = asyncLocalStorage.getStore().get('requestId');
console.log(`Handling request with ID: ${requestId}`);
res.send(`Hello, Request ID: ${requestId}`);
});
app.listen(3000, () => {
console.log('Server listening on port 3000');
});
ãã®äŸã§ã¯ïŒ
AsyncLocalStorageã®ã€ã³ã¹ã¿ã³ã¹ãäœæããŸãã- Expressã®ããã«ãŠã§ã¢ã䜿çšããŠãååä¿¡ãªã¯ãšã¹ããã€ã³ã¿ãŒã»ããããŸãã
- ããã«ãŠã§ã¢å
ã§ã
uuidv4()ã䜿çšããŠäžæã®ãªã¯ãšã¹ãIDãçæããŸãã asyncLocalStorage.run()ãåŒã³åºããŠæ°ããéåæã³ã³ããã¹ããäœæããŸããã¹ãã¢ã¯ãã³ã³ããã¹ã倿°ãä¿æããMapã§åæåããŸããrun()ã³ãŒã«ããã¯å ã§ãasyncLocalStorage.getStore().set('requestId', requestId)ã䜿çšããŠã¹ãã¢ã«requestIdãèšå®ããŸãã- 次ã«
next()ãåŒã³åºããŠã次ã®ããã«ãŠã§ã¢ãŸãã¯ã«ãŒããã³ãã©ã«å¶åŸ¡ãæž¡ããŸãã - ã«ãŒããã³ãã©ïŒ
app.get('/')ïŒã§ã¯ãasyncLocalStorage.getStore().get('requestId')ã䜿çšããŠã¹ãã¢ããrequestIdãååŸããŸãã
ããã§ããªã¯ãšã¹ããã³ãã©å
ã§ã©ãã ãå€ãã®éåææäœãããªã¬ãŒãããŠããåžžã«asyncLocalStorage.getStore().get('requestId')ã䜿çšããŠãªã¯ãšã¹ãIDã«ã¢ã¯ã»ã¹ã§ããŸãã
äŸ2ïŒãŠãŒã¶ãŒèªèšŒãšèªå¯
ããäžã€ã®äžè¬çãªãŠãŒã¹ã±ãŒã¹ã¯ããŠãŒã¶ãŒã®èªèšŒããã³èªå¯æ
å ±ã®ç®¡çã§ãããŠãŒã¶ãŒãèªèšŒãããã®ãŠãŒã¶ãŒIDãååŸããããã«ãŠã§ã¢ããããšããŸããAsyncLocalStorageã«ãŠãŒã¶ãŒIDãä¿åããããšã§ãåŸç¶ã®ããã«ãŠã§ã¢ãã«ãŒããã³ãã©ã§å©çšã§ããããã«ãªããŸãã
const express = require('express');
const { AsyncLocalStorage } = require('async_hooks');
const app = express();
const asyncLocalStorage = new AsyncLocalStorage();
// Authentication Middleware (Example)
const authenticateUser = (req, res, next) => {
// Simulate user authentication (replace with your actual logic)
const userId = req.headers['x-user-id'] || 'guest'; // Get User ID from Header
asyncLocalStorage.run(new Map(), () => {
asyncLocalStorage.getStore().set('userId', userId);
console.log(`User authenticated with ID: ${userId}`);
next();
});
};
app.use(authenticateUser);
app.get('/profile', (req, res) => {
const userId = asyncLocalStorage.getStore().get('userId');
console.log(`Accessing profile for user ID: ${userId}`);
res.send(`Profile for User ID: ${userId}`);
});
app.listen(3000, () => {
console.log('Server listening on port 3000');
});
ãã®äŸã§ã¯ãauthenticateUserããã«ãŠã§ã¢ããŠãŒã¶ãŒIDãååŸãïŒããã§ã¯ããããŒã®èªã¿åãã§ã·ãã¥ã¬ãŒãïŒããããAsyncLocalStorageã«ä¿åããŸãããã®åŸã/profileã«ãŒããã³ãã©ã¯ãæç€ºçãªãã©ã¡ãŒã¿ãšããŠåãåãããšãªããŠãŒã¶ãŒIDã«ã¢ã¯ã»ã¹ã§ããŸãã
äŸ3ïŒããŒã¿ããŒã¹ãã©ã³ã¶ã¯ã·ã§ã³ç®¡ç
ããŒã¿ããŒã¹ãã©ã³ã¶ã¯ã·ã§ã³ãé¢ããã·ããªãªã§ã¯ãAsyncLocalStorageã䜿çšããŠãã©ã³ã¶ã¯ã·ã§ã³ã³ã³ããã¹ãã管çã§ããŸããããŒã¿ããŒã¹æ¥ç¶ãŸãã¯ãã©ã³ã¶ã¯ã·ã§ã³ãªããžã§ã¯ããAsyncLocalStorageã«ä¿åããããšã§ãç¹å®ã®ãªã¯ãšã¹ãå
ã®ãã¹ãŠã®ããŒã¿ããŒã¹æäœãåããã©ã³ã¶ã¯ã·ã§ã³ã䜿çšããããšãä¿èšŒã§ããŸãã
const express = require('express');
const { AsyncLocalStorage } = require('async_hooks');
const app = express();
const asyncLocalStorage = new AsyncLocalStorage();
// Simulate a database connection
const db = {
query: (sql, callback) => {
const transactionId = asyncLocalStorage.getStore()?.get('transactionId') || 'No Transaction';
console.log(`Executing SQL: ${sql} in Transaction: ${transactionId}`);
// Simulate database query execution
setTimeout(() => {
callback(null, { success: true });
}, 50);
},
};
// Middleware to start a transaction
const startTransaction = (req, res, next) => {
const transactionId = Math.random().toString(36).substring(2, 15); // Generate a random transaction ID
asyncLocalStorage.run(new Map(), () => {
asyncLocalStorage.getStore().set('transactionId', transactionId);
console.log(`Starting transaction: ${transactionId}`);
next();
});
};
app.use(startTransaction);
app.get('/data', (req, res) => {
db.query('SELECT * FROM data', (err, result) => {
if (err) {
return res.status(500).send('Error querying data');
}
res.send('Data retrieved successfully');
});
});
app.listen(3000, () => {
console.log('Server listening on port 3000');
});
ãã®ç°¡ç¥åãããäŸã§ã¯ïŒ
startTransactionããã«ãŠã§ã¢ã¯ãã©ã³ã¶ã¯ã·ã§ã³IDãçæãããããAsyncLocalStorageã«ä¿åããŸãã- ã·ãã¥ã¬ãŒãããã
db.query颿°ã¯ãã¹ãã¢ãããã©ã³ã¶ã¯ã·ã§ã³IDãååŸããŠãã°ã«åºåããéåæããŒã¿ããŒã¹æäœå ã§ãã©ã³ã¶ã¯ã·ã§ã³ã³ã³ããã¹ããå©çšå¯èœã§ããããšã瀺ããŸãã
é«åºŠãªäœ¿çšæ³ãšèæ ®äºé
ããã«ãŠã§ã¢ãšã³ã³ããã¹ãäŒæ
AsyncLocalStorageã¯ãããã«ãŠã§ã¢ãã§ãŒã³ã«ãããŠç¹ã«æçšã§ããåããã«ãŠã§ã¢ã¯å
±æã³ã³ããã¹ãã«ã¢ã¯ã»ã¹ã»å€æŽã§ããè€éãªåŠçãã€ãã©ã€ã³ã容æã«æ§ç¯ã§ããŸãã
ããã«ãŠã§ã¢é¢æ°ãã³ã³ããã¹ããé©åã«äŒæããããã«èšèšãããŠããããšã確èªããŠãã ãããasyncLocalStorage.run()ãŸãã¯asyncLocalStorage.enterWith()ã䜿çšããŠéåææäœãã©ããããã³ã³ããã¹ãã®æµããç¶æããŸãã
ãšã©ãŒãã³ããªã³ã°ãšã¯ãªãŒã³ã¢ãã
AsyncLocalStorageã䜿çšããéã«ã¯ãé©åãªãšã©ãŒãã³ããªã³ã°ãäžå¯æ¬ ã§ããäŸå€ãé©åã«åŠçããã³ã³ããã¹ãã«é¢é£ä»ãããããªãœãŒã¹ãã¯ãªãŒã³ã¢ããããããã«ããŠãã ãããtry...finallyãããã¯ã䜿çšããŠããšã©ãŒãçºçããå Žåã§ããªãœãŒã¹ã確å®ã«è§£æŸãããããã«ããããšãæ€èšããŠãã ããã
ããã©ãŒãã³ã¹ã«é¢ããèæ ®äºé
AsyncLocalStorageã¯ã³ã³ããã¹ãã管çãã䟿å©ãªæ¹æ³ãæäŸããŸããããã®ããã©ãŒãã³ã¹ãžã®åœ±é¿ã«æ³šæããããšãäžå¯æ¬ ã§ããç¹ã«é«ã¹ã«ãŒãããã®ã¢ããªã±ãŒã·ã§ã³ã§ã¯ãAsyncLocalStorageã®é床ãªäœ¿çšã¯ãªãŒããŒããããåŒãèµ·ããå¯èœæ§ããããŸããã³ãŒãããããã¡ã€ãªã³ã°ããŠæœåšçãªããã«ããã¯ãç¹å®ããé©å®æé©åããŠãã ããã
AsyncLocalStorageã«å€§éã®ããŒã¿ãä¿åããããšã¯é¿ããŠãã ãããå¿
èŠãªã³ã³ããã¹ã倿°ã®ã¿ãä¿åããŠãã ããããã倧ããªãªããžã§ã¯ããä¿åããå¿
èŠãããå Žåã¯ããªããžã§ã¯ãèªäœã§ã¯ãªããããããžã®åç
§ãä¿åããããšãæ€èšããŠãã ããã
AsyncLocalStorageã®ä»£æ¿ææ®µ
AsyncLocalStorageã¯åŒ·åãªããŒã«ã§ãããç¹å®ã®ããŒãºããã¬ãŒã ã¯ãŒã¯ã«ãã£ãŠã¯ãéåæã³ã³ããã¹ãã管çããããã®ä»£æ¿ã¢ãããŒããååšããŸãã
- æç€ºçãªã³ã³ããã¹ãã®åãæž¡ãïŒåè¿°ã®ããã«ãã³ã³ããã¹ã倿°ã颿°ã®åŒæ°ãšããŠæç€ºçã«æž¡ãããšã¯ãåºæ¬çã§ã¯ãããŸãããããŸãæŽç·ŽãããŠããªãã¢ãããŒãã§ãã
- ã³ã³ããã¹ããªããžã§ã¯ãïŒå°çšã®ã³ã³ããã¹ããªããžã§ã¯ããäœæããŠåŒãåãããšã§ãåã ã®å€æ°ãæž¡ãå Žåã«æ¯ã¹ãŠå¯èªæ§ãåäžããŸãã
- ãã¬ãŒã ã¯ãŒã¯åºæã®ãœãªã¥ãŒã·ã§ã³ïŒå€ãã®ãã¬ãŒã ã¯ãŒã¯ã¯ãç¬èªã®ã³ã³ããã¹ã管çã¡ã«ããºã ãæäŸããŠããŸããäŸãã°ãNestJSã¯ãªã¯ãšã¹ãã¹ã³ãŒãã®ãããã€ããŒãæäŸããŠããŸãã
ã°ããŒãã«ãªèŠç¹ãšãã¹ããã©ã¯ãã£ã¹
ã°ããŒãã«ãªæèã§éåæã³ã³ããã¹ããæ±ãéã«ã¯ã次ã®ç¹ãèæ ®ããŠãã ããïŒ
- ã¿ã€ã ãŸãŒã³ïŒã³ã³ããã¹ãå ã§æ¥ææ å ±ãæ±ãéã«ã¯ãã¿ã€ã ãŸãŒã³ã«æ³šæããŠãã ãããææ§ããé¿ããããã«ãã¿ã€ã ã¹ã¿ã³ããšå ±ã«ã¿ã€ã ãŸãŒã³æ å ±ãä¿åããŸãããã
- ããŒã«ãªãŒãŒã·ã§ã³ïŒã¢ããªã±ãŒã·ã§ã³ãå€èšèªããµããŒãããå ŽåããŠãŒã¶ãŒã®ãã±ãŒã«ãã³ã³ããã¹ãã«ä¿åããã³ã³ãã³ããæ£ããèšèªã§è¡šç€ºãããããã«ããŸãã
- é貚ïŒã¢ããªã±ãŒã·ã§ã³ãéèååŒãæ±ãå ŽåããŠãŒã¶ãŒã®é貚ãã³ã³ããã¹ãã«ä¿åããéé¡ãæ£ãã衚瀺ãããããã«ããŸãã
- ããŒã¿åœ¢åŒïŒç°ãªãå°åã§äœ¿çšãããããŸããŸãªããŒã¿åœ¢åŒã«æ³šæããŠãã ãããäŸãã°ãæ¥ä»åœ¢åŒãæ°å€åœ¢åŒã¯å€§ããç°ãªãããšããããŸãã
çµè«
AsyncLocalStorageã¯ãéåæJavaScriptç°å¢ã§ãªã¯ãšã¹ãã¹ã³ãŒã倿°ã管çããããã®ã匷åã§æŽç·Žããããœãªã¥ãŒã·ã§ã³ãæäŸããŸããéåæã®å¢çãè¶ããŠæ°žç¶çãªã³ã³ããã¹ããäœæããããšã«ãããã³ãŒããç°¡çŽ åããçµåãæžãããä¿å®æ§ãåäžãããŸãããã®æ©èœãšéçãçè§£ããããšã§ãAsyncLocalStorageãæŽ»çšããŠãå
ç¢ã§ã¹ã±ãŒã©ãã«ããã€ã°ããŒãã«å¯Ÿå¿ã®ã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ã§ããŸãã
éåæã³ã³ããã¹ããç¿åŸããããšã¯ãéåæã³ãŒããæ±ããã¹ãŠã®JavaScriptéçºè
ã«ãšã£ãŠäžå¯æ¬ ã§ããAsyncLocalStorageããã®ä»ã®ã³ã³ããã¹ã管çæè¡ãåãå
¥ããŠãããã¯ãªãŒã³ã§ãä¿å®ãããããä¿¡é Œæ§ã®é«ãã¢ããªã±ãŒã·ã§ã³ãäœæããŸãããã