åçã€ã³ããŒãã«ããã¢ããªã±ãŒã·ã§ã³èµ·åããã»ã¹ã®ãªãã¡ã¯ã¿ãªã³ã°#
ã¯ããã«#
Misskey ããã¯ãšã³ãã¯ãNode.js ã® cluster ã¢ãžã¥ãŒã«ã䜿çšããŠãã¹ã¿ãŒããã»ã¹ãšã¯ãŒã«ãŒããã»ã¹ã«åå²ããã忣ã¢ãŒããã¯ãã£ã§åäœããŸããåŸæ¥ã®å®è£ ã§ã¯ãããã»ã¹ã®åœ¹å²ã«é¢ä¿ãªãããã¹ãŠã®ããã»ã¹ãåãã¢ãžã¥ãŒã«ã°ã©ããèªã¿èŸŒãã§ããŸãããããã«ããããã¹ã¿ãŒããã»ã¹ãã¯ãŒã«ãŒãã¹ããŒã³ããéã«ãäžèŠãªãµãŒããŒãµã€ãã³ãŒããŸã§å«ããå®å šãªã¢ãžã¥ãŒã«ã°ã©ããåã€ã³ããŒããããã³ãŒã«ãã¹ã¿ãŒãæéãå€§å¹ ã«å¢å ããŠããŸããã
PR #1410 "enhance: èµ·åãã listen ãŸã§ãããæéãæžãã"ïŒ2026 幎 1 æ 24 æ¥ããŒãžïŒã¯ããã®åé¡ã解決ããããã«åçã€ã³ããŒãïŒdynamic importsïŒãå°å ¥ãããã¹ã¿ãŒãšã¯ãŒã«ãŒã®ããã»ã¹ã³ãŒããåé¢ããŸããããã®æé©åã«ãããåããã»ã¹ã¿ã€ãã«å¿ èŠãªã³ãŒãã®ã¿ãèªã¿èŸŒãŸããããã«ãªããã¯ã©ã¹ã¿ãŒç°å¢ã§ã®ã³ãŒã«ãã¹ã¿ãŒãæéãå€§å¹ ã«ççž®ãããŸããã
æ¬ããã¥ã¡ã³ãã§ã¯ããã®ãªãã¡ã¯ã¿ãªã³ã°ã®å®è£ 詳现ãããã©ãŒãã³ã¹ãžã®åœ±é¿ãããã³ããã¯ãšã³ããµãŒããŒãšãžã§ããã¥ãŒã®èµ·åããã©ãŒãã³ã¹ã®æ¹åã«ã€ããŠè§£èª¬ããŸãã
å®è£ ã®äž»èŠãªå€æŽç¹#
1. ãšã³ããªãŒãã€ã³ãã®ãªãã¡ã¯ã¿ãªã³ã° (packages/backend/src/boot/entry.ts)#
ãšã³ããªãŒãã€ã³ãã¯ãcluster.isPrimaryãšcluster.isWorkerã®æ¡ä»¶åå²ãšåçã€ã³ããŒãã䜿çšããŠãåããã»ã¹ã¿ã€ãã«å¿
èŠãªã³ãŒãã®ã¿ãèªã¿èŸŒã¿ãŸãïŒ
if (cluster.isPrimary || envOption.disableClustering) {
// NOTE: Avoid loading worker-side code in the master process (and vice-versa).
// This reduces cold-start time in clustered environments where spawning a worker
// would otherwise re-import the full master/server module graph.
const { masterMain } = await import('./master.js');
await masterMain();
if (cluster.isPrimary) {
ev.mount();
}
}
if (cluster.isWorker) {
const { workerMain } = await import('./worker.js');
await workerMain();
}
äž»èŠãªå©ç¹ïŒ
- ãã¹ã¿ãŒããã»ã¹ã¯
master.jsã®ã¿ãèªã¿èŸŒã - ã¯ãŒã«ãŒããã»ã¹ã¯
worker.jsã®ã¿ãèªã¿èŸŒã - ã¯ãŒã«ãŒãã¹ããŒã³ããéã®åé·ãªã¢ãžã¥ãŒã«ã°ã©ãã®èªã¿èŸŒã¿ã鲿¢
- ESM äºææ§ã®ããã«
.jsæ¡åŒµåã䜿çš
ãã®å®è£ ã®æ žå¿ã¯ãã³ãŒãå ã®ã³ã¡ã³ãã§æç¢ºã«èª¬æãããŠããããã«ãããã¹ã¿ãŒããã»ã¹ã§ã¯ãŒã«ãŒåŽã®ã³ãŒããèªã¿èŸŒãŸãªãïŒããã³ãã®éïŒãããšã§ããããã«ãããã¯ã©ã¹ã¿ãŒç°å¢ã§ã¯ãŒã«ãŒãã¹ããŒã³ããéã«ãå®å šãªãã¹ã¿ãŒ / ãµãŒããŒã¢ãžã¥ãŒã«ã°ã©ããåã€ã³ããŒããããããšãåé¿ããã³ãŒã«ãã¹ã¿ãŒãæéãåæžããŸãã
2. å
±éã¢ãžã¥ãŒã«ã®æé©å (packages/backend/src/boot/common.ts)#
common.tsã®server()ãšjobQueue()ã®äž¡é¢æ°ã¯ãåçã€ã³ããŒãã䜿çšããŠéãã¢ãžã¥ãŒã«ã®èªã¿èŸŒã¿ãé
å»¶ãããŸãã
server() 颿°#
export async function server() {
const { MainModule } = await import('../MainModule.js');
const { ServerService } = await import('../server/ServerService.js');
const { ChartManagementService } = await import('../core/chart/ChartManagementService.js');
const { QueueStatsService } = await import('../daemons/QueueStatsService.js');
const app = await NestFactory.createApplicationContext(MainModule, {
logger: new NestLogger(),
});
app.enableShutdownHooks();
const serverService = app.get(ServerService);
await serverService.launch();
if (process.env.NODE_ENV !== 'test') {
app.get(ChartManagementService).start();
app.get(QueueStatsService).start();
}
return app;
}
ãã®é¢æ°ã¯ãHTTP ãµãŒããŒã®èµ·åã«å¿ èŠãªã¢ãžã¥ãŒã«ã®ã¿ããå®éã«é¢æ°ãåŒã³åºããããšãã«åçã«èªã¿èŸŒã¿ãŸãã
jobQueue() 颿°#
export async function jobQueue() {
const { QueueProcessorModule } = await import('../queue/QueueProcessorModule.js');
const { QueueProcessorService } = await import('../queue/QueueProcessorService.js');
const { ChartManagementService } = await import('../core/chart/ChartManagementService.js');
const jobQueue = await NestFactory.createApplicationContext(QueueProcessorModule, {
logger: new NestLogger(),
});
jobQueue.enableShutdownHooks();
jobQueue.get(QueueProcessorService).start();
jobQueue.get(ChartManagementService).start();
return jobQueue;
}
åæ§ã«ããžã§ããã¥ãŒåŠçã«å¿ èŠãªã¢ãžã¥ãŒã«ã®ã¿ãé å»¶èªã¿èŸŒã¿ããŸãã
é å»¶èªã¿èŸŒã¿ãããã¢ãžã¥ãŒã«ïŒ
MainModule- ãµãŒããŒã®äŸåé¢ä¿ServerService- HTTP ãµãŒããŒQueueProcessorModule- ãžã§ããã¥ãŒã®äŸåé¢ä¿QueueProcessorService- ãžã§ãåŠçChartManagementService- ã¡ããªã¯ã¹ / åæQueueStatsService- ãã¥ãŒç£èŠ
äž¡é¢æ°ã¯åããã¿ãŒã³ã«åŸããŸãïŒ
- 颿°ã®å
é ã§å¿
èŠãªã¢ãžã¥ãŒã«ã
await import()ã§åçã«ã€ã³ããŒã - NestJS ã¢ããªã±ãŒã·ã§ã³ã³ã³ããã¹ããäœæ
- ãµãŒãã¹ãåæåããŠèµ·å
- ã¢ããªã±ãŒã·ã§ã³ã³ã³ããã¹ããè¿ã
ãã®èšèšã«ãããéã NestJS ã¢ãžã¥ãŒã«ïŒMainModuleãQueueProcessorModuleïŒã¯ãããããã®é¢æ°ãå®éã«å®è¡ããããšãã«ã®ã¿èªã¿èŸŒãŸããã¢ãžã¥ãŒã«è©äŸ¡æã«ã¯èªã¿èŸŒãŸããŸããã
ããã»ã¹å¥ã®èµ·ååäœ#
ãã¹ã¿ãŒããã»ã¹ (master.ts)#
ãã¹ã¿ãŒããã»ã¹ã¯ãç°å¢ãªãã·ã§ã³ã«åºã¥ããŠãµãŒãã¹ãæ¡ä»¶ä»ãã§èµ·åããŸãïŒ
if (envOption.disableClustering) {
if (envOption.onlyServer) {
await server();
} else if (envOption.onlyQueue) {
await jobQueue();
} else {
await server();
await jobQueue();
}
} else {
if (envOption.onlyServer) {
// nop
} else if (envOption.onlyQueue) {
// nop
} else {
await server();
}
await spawnWorkers(config.clusterLimit);
}
èµ·åã·ããªãªïŒ
- ã¯ã©ã¹ã¿ãŒã¢ãŒãïŒããã©ã«ãïŒ: ãã¹ã¿ãŒã
server()ãèµ·åããŠãããjobQueue()çšã®ã¯ãŒã«ãŒãã¹ããŒã³ - ã·ã³ã°ã«ããã»ã¹ã¢ãŒã: ãã¹ã¿ãŒã
server()ãšjobQueue()ã®äž¡æ¹ãå®è¡ - ãµãŒããŒå°çšã¢ãŒã: HTTP ãµãŒããŒã®ã¿ããžã§ãåŠçãªã
- ãã¥ãŒå°çšã¢ãŒã: ãžã§ãåŠçã®ã¿ãHTTP ãµãŒããŒãªã
ã¯ãŒã«ãŒããã»ã¹ (worker.ts)#
ã¯ãŒã«ãŒããã»ã¹ã¯ãžã§ããã¥ãŒåŠçãæ åœããŸãïŒ
if (envOption.onlyServer) {
await server();
} else if (envOption.onlyQueue) {
await jobQueue();
} else {
await jobQueue();
}
ããã©ã«ãåäœïŒ ã¯ãŒã«ãŒã¯éåžžãããã©ã«ãã§jobQueue()ãå®è¡ãããµãŒããŒãµã€ãã¢ãžã¥ãŒã«ã®èªã¿èŸŒã¿ãåé¿ããŸãã
ããã©ãŒãã³ã¹ãžã®åœ±é¿#
ã³ãŒã«ãã¹ã¿ãŒãæéã®åæž#
PR #1410ã«ããã°ããã®ãªãã¡ã¯ã¿ãªã³ã°ã¯èµ·åãã listen ãŸã§ãããæéãèããççž®ããŸãã
åçã€ã³ããŒããã³ãŒã«ãã¹ã¿ãŒãæéãåæžããä»çµã¿ïŒ
1. åé·ãªã¢ãžã¥ãŒã«èªã¿èŸŒã¿ã®é²æ¢#
åŸæ¥ã®å®è£
ã§ã¯ãã¯ã©ã¹ã¿ãŒã¢ãŒãã§ãã¹ã¿ãŒãã¯ãŒã«ãŒãã¹ããŒã³ããéãåã¯ãŒã«ãŒããã»ã¹ããµãŒããŒãµã€ãã³ãŒããå«ãå®å
šãªã¢ãžã¥ãŒã«ã°ã©ããåã€ã³ããŒãããŠããŸãããåçã€ã³ããŒãã«ãããã¯ãŒã«ãŒã¯worker.jsãšãžã§ããã¥ãŒã®äŸåé¢ä¿ã®ã¿ãèªã¿èŸŒãããã«ãªããŸããã
ããã¯ãNode.js ã® cluster ã¢ãžã¥ãŒã«ã®åäœåçã«èµ·å ããŸããã¯ã©ã¹ã¿ãŒã§ã¯ãŒã«ãŒãã¹ããŒã³ãããšãæ°ããããã»ã¹ãäœæãããåããšã³ããªãŒãã€ã³ãããå®è¡ãéå§ãããŸããåŸæ¥ã®éçã€ã³ããŒãã§ã¯ããã¹ãŠã®ã¢ãžã¥ãŒã«ãè©äŸ¡æã«èªã¿èŸŒãŸããŠãããããã¯ãŒã«ãŒããã»ã¹ã§ãäžèŠãªãµãŒããŒã¢ãžã¥ãŒã«ãèªã¿èŸŒãŸããŠããŸããã
2. éãã¢ãžã¥ãŒã«è©äŸ¡ã®é å»¶#
NestJS ã¢ãžã¥ãŒã«ïŒMainModuleãQueueProcessorModuleïŒã¯ãããããã®é¢æ°ãåŒã³åºããããšãã«ã®ã¿èªã¿èŸŒãŸããã¢ãžã¥ãŒã«è©äŸ¡æã«ã¯èªã¿èŸŒãŸããŸããã
NestJS ã¢ãžã¥ãŒã«ã¯ãäŸåæ§æ³šå ¥ã³ã³ããã®åæåããããã€ããŒã®ç»é²ãã¡ã¿ããŒã¿ã®åŠçãªã©ãå€ãã®éãåŠçã䌎ããŸããããããé å»¶ãããããšã§ãåæèµ·åæã®ãªãŒããŒããããå€§å¹ ã«åæžãããŸãã
3. ããã»ã¹åºæã®ã³ãŒããã¹#
ãã¹ã¿ãŒãšã¯ãŒã«ãŒããã»ã¹ã¯å®å šã«åé¢ãããã³ãŒããã©ã³ããèªã¿èŸŒããããäŸåé¢ä¿ã®çžäºæ±æãåé¿ããŸããåããã»ã¹ã¯ããã®åœ¹å²ã«å¿ èŠãªæå°éã®ã³ãŒãã®ã¿ãã¡ã¢ãªã«ä¿æããŸãã
ããã¯ãšã³ããµãŒããŒã®èµ·åããã©ãŒãã³ã¹#
server() 颿°ã¯ãé
å»¶èªã¿èŸŒã¿ã«ãã以äžã®æ©æµãåããŸãïŒ
- æ¡ä»¶ä»ãã¢ãžã¥ãŒã«èªã¿èŸŒã¿:
ServerServiceããã³ HTTP é¢é£ã®äŸåé¢ä¿ã¯ãå¿ èŠãªãšãã«ã®ã¿èªã¿èŸŒãŸããŸã - ã¯ã©ã¹ã¿ãŒã¢ãŒãã§ã®æé©å: ã¯ãŒã«ãŒããã»ã¹ã¯ãµãŒããŒã¢ãžã¥ãŒã«ãäžåèªã¿èŸŒãŸãªããããã¡ã¢ãªäœ¿çšéãå€§å¹ ã«åæžãããŸã
- 段éçãªåæå:
ChartManagementServiceãšQueueStatsServiceã®åæåã¯ããµãŒããŒèµ·ååŸãŸã§é å»¶ãããŸã
ãã®èšèšã«ãããã¯ã©ã¹ã¿ãŒç°å¢ã§ã¯ä»¥äžã®ãããªèµ·åãããŒãå®çŸãããŸãïŒ
- ãã¹ã¿ãŒããã»ã¹ãèµ·åãã
entry.tsã§master.jsã®ã¿ãã€ã³ããŒã - ãã¹ã¿ãŒã
server()ãåŒã³åºãããã®æç¹ã§åããŠMainModuleãšServerServiceãã€ã³ããŒãããã - HTTP ãµãŒããŒãèµ·åãããªã¯ãšã¹ãã®åãä»ããéå§
- ã¯ãŒã«ãŒãã¹ããŒã³ããããããµãŒããŒé¢é£ã®ã³ãŒãã¯äžåèªã¿èŸŒãŸãªã
ãžã§ããã¥ãŒã®èµ·åããã©ãŒãã³ã¹#
jobQueue() 颿°ãåæ§ã®æé©åãå®çŸããŸãïŒ
- ãã¥ãŒåºæã®ã¢ãžã¥ãŒã«èªã¿èŸŒã¿:
QueueProcessorModuleã®äŸåé¢ä¿ã¯ããã¥ãŒèµ·åæã«ã®ã¿èªã¿èŸŒãŸããŸã - ããã»ã¹åé¢: ã¯ã©ã¹ã¿ãŒã¢ãŒãã§ã¯ããã¹ã¿ãŒã¯ãã¥ãŒã¢ãžã¥ãŒã«ãèªã¿èŸŒãŸãïŒã¯ãŒã«ãŒãåŠçïŒãHTTP ãµãŒããŒã®ã¡ã¢ãªãããããªã³ããåæž
- ç¬ç«ãã NestJS ã³ã³ããã¹ã: ãžã§ããã¥ãŒåŠçã HTTP ãµãŒããŒããåé¢ããç¬ç«ããã¢ããªã±ãŒã·ã§ã³ã³ã³ããã¹ãã§å®è¡
ãžã§ããã¥ãŒã®èµ·åãããŒã¯ä»¥äžã®ããã«ãªããŸãïŒ
- ã¯ãŒã«ãŒããã»ã¹ãèµ·åãã
entry.tsã§worker.jsã®ã¿ãã€ã³ããŒã - ã¯ãŒã«ãŒã
jobQueue()ãåŒã³åºãããã®æç¹ã§åããŠQueueProcessorModuleãšQueueProcessorServiceãã€ã³ããŒãããã - ãžã§ããã¥ãŒåŠçãéå§ãããããã¯ã°ã©ãŠã³ãã¿ã¹ã¯ã®å®è¡ãéå§
- HTTP ãµãŒããŒé¢é£ã®ã³ãŒãã¯äžåèªã¿èŸŒãŸãããã¡ã¢ãªãç¯çŽ
ã¢ãŒããã¯ãã£å³#
以äžã®å³ã¯ãåçã€ã³ããŒãã«ããããã»ã¹åé¢ã瀺ããŠããŸãïŒ
é¢é£ããæé©å#
ãã®ãªãã¡ã¯ã¿ãªã³ã°ã¯ãMisskey ã³ãŒãããŒã¹å šäœã§æ¡çšãããŠããåçã€ã³ããŒããã¿ãŒã³ã®äžéšã§ãïŒ
PR #234ïŒ2023 幎 11 æïŒ- ã¯ã©ã¹ã¿ãŒç°å¢ã§ã®èµ·åããžãã¯ä¿®æ£#
PR #234ã¯ãworkerMain()ãcluster.isWorkerãçã®å Žåã«ã®ã¿åŒã³åºãããããã«èµ·åããžãã¯ãä¿®æ£ããŸãããããã«ãããããã»ã¹åé¢ã®ããã®ããæç¢ºãªåºç€ãæŽåãããŸããã
PR #1163ïŒ2025 幎 11 æïŒ- AI ãµãŒãã¹ã§ã®é å»¶èªã¿èŸŒã¿ãã¿ãŒã³#
PR #1163ã¯ãAI ãµãŒãã¹ã§nsfwjsã©ã€ãã©ãªã®é
å»¶èªã¿èŸŒã¿ãå®è£
ããŸãããéçã€ã³ããŒããåçã€ã³ããŒãïŒconst nsfw = await import('nsfwjs')ïŒã«çœ®ãæããã©ã€ãã©ãªãã¢ããªã±ãŒã·ã§ã³èµ·åæã§ã¯ãªããå®éã«æ€åºãªã¯ãšã¹ããå¿
èŠãªãšãã«ã®ã¿èªã¿èŸŒãŸããããã«ããŸããã
ããã¯ãPR #1410 ãšåãèšèšååã瀺ããŠããŸãïŒèµ·åæã®ãªãŒããŒããããšã¡ã¢ãªãããããªã³ããåæžããããã«ãéãäŸåé¢ä¿ãé å»¶èªã¿èŸŒã¿ãããšãããã¿ãŒã³ã§ãã
ãŸãšã#
åçã€ã³ããŒãã䜿çšããèµ·åããã»ã¹ã®ãªãã¡ã¯ã¿ãªã³ã°ã¯ãMisskey ããã¯ãšã³ãã®ããã©ãŒãã³ã¹ãå€§å¹ ã«åäžãããŸãããäž»ãªææã¯ä»¥äžã®éãã§ãïŒ
-
ããã»ã¹åé¢ã®å®çŸ:
cluster.isPrimaryãšcluster.isWorkerã®æ¡ä»¶åå²ã«ãããåããã»ã¹ãå¿ èŠãªã³ãŒãã®ã¿ãèªã¿èŸŒãããã«ãªããŸãã -
ã³ãŒã«ãã¹ã¿ãŒãæéã®ççž®: ã¯ãŒã«ãŒã®ã¹ããŒã³æã«å®å šãªã¢ãžã¥ãŒã«ã°ã©ããåã€ã³ããŒããããªããªããã¯ã©ã¹ã¿ãŒç°å¢ã§ã®èµ·åæéãèããççž®ãããŸãã
-
ã¢ãžã¥ãŒã«èªã¿èŸŒã¿ã®æé©å:
server()ãšjobQueue()颿°å ã§ã®åçã€ã³ããŒãã«ãããéã NestJS ã¢ãžã¥ãŒã«ã®è©äŸ¡ãå®éã«å¿ èŠã«ãªããŸã§é å»¶ãããŸã -
ã¡ã¢ãªå¹çã®åäž: åããã»ã¹ã圹å²ã«å¿ èŠãªæå°éã®ã³ãŒãã®ã¿ãã¡ã¢ãªã«ä¿æããããšã§ããªãœãŒã¹æ¶è²»ãåæžãããŸãã
-
æè»ãªèµ·åæ§æ: ç°å¢ãªãã·ã§ã³ã«ããããµãŒããŒå°çšããã¥ãŒå°çšããŸãã¯ãã®äž¡æ¹ã®ã¢ãŒãã§å®è¡ã§ããæè»æ§ãæäŸãããŸã
ãã®ã¢ãŒããã¯ãã£ãã¿ãŒã³ã¯ãå€§èŠæš¡ãª Node.js ã¢ããªã±ãŒã·ã§ã³ã«ãããã¯ã©ã¹ã¿ãŒç°å¢ã§ã®ããã©ãŒãã³ã¹æé©åã®ãã¹ããã©ã¯ãã£ã¹ã瀺ããŠããŸããåçã€ã³ããŒããšããã»ã¹åé¢ãçµã¿åãããããšã§ãã¹ã±ãŒã©ããªãã£ãšå¹çæ§ã®äž¡æ¹ãéæã§ããŸãã