mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-06 17:08:10 +00:00
perf(backend): parallelize independent startup initializers (#816)
The boot path awaited SelfUpdateService.initialize, DockerEventManager.start, and TrivyService.initialize one at a time even though none of them depend on each other. Group them into a single Promise.all so total cold-start time is the slowest one rather than the sum. Also convert the inner `docker compose version` probe in SelfUpdateService.initialize from execFileSync to execFileAsync. Without that, the synchronous spawn would block the event loop for up to 5 seconds and silently serialize the other two members of the parallel block, defeating the parallelization win for in-container deployments. The synchronous service starts (Monitor, AutoHeal, ImageUpdate, Scheduler, Mfa) are grouped together up front. They schedule timers whose first ticks fire 5+ seconds out, so they safely run alongside the awaited block.
This commit is contained in:
@@ -29,27 +29,29 @@ export async function startServer(server: Server): Promise<void> {
|
||||
console.error('Migration failed:', error);
|
||||
}
|
||||
|
||||
// Synchronous starts: schedule background timers and continue. None of
|
||||
// these fire their first tick for at least a few seconds, so they
|
||||
// safely run alongside the async initializers below.
|
||||
LicenseService.getInstance().initialize();
|
||||
|
||||
await SelfUpdateService.getInstance().initialize();
|
||||
|
||||
MonitorService.getInstance().start();
|
||||
AutoHealService.getInstance().start();
|
||||
|
||||
await DockerEventManager.getInstance().start();
|
||||
|
||||
await TrivyService.getInstance().initialize();
|
||||
|
||||
ImageUpdateService.getInstance().start();
|
||||
|
||||
SchedulerService.getInstance().start();
|
||||
MfaService.getInstance().start();
|
||||
|
||||
// Async initializers are independent of each other; run in parallel
|
||||
// so total boot time is the slowest one rather than the sum.
|
||||
await Promise.all([
|
||||
SelfUpdateService.getInstance().initialize(),
|
||||
DockerEventManager.getInstance().start(),
|
||||
TrivyService.getInstance().initialize(),
|
||||
]);
|
||||
|
||||
// Fire-and-forget housekeeping; logged but never awaited.
|
||||
sweepStaleGitTempDirs().catch((err) => {
|
||||
console.warn('[GitSource] Temp dir sweep failed:', (err as Error).message);
|
||||
});
|
||||
|
||||
MfaService.getInstance().start();
|
||||
|
||||
const isPilotAgent = process.env.SENCHO_MODE === 'pilot';
|
||||
const listenHost = isPilotAgent ? '127.0.0.1' : undefined;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { execFileSync, execFile } from 'child_process';
|
||||
import { execFile } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
import * as fs from 'fs';
|
||||
import DockerController from './DockerController';
|
||||
@@ -63,9 +63,12 @@ class SelfUpdateService {
|
||||
return;
|
||||
}
|
||||
|
||||
// Verify docker compose CLI is available inside the container
|
||||
// Verify docker compose CLI is available inside the container.
|
||||
// execFileAsync (not Sync) so the parallel boot-task block in
|
||||
// bootstrap/startup.ts can actually run TrivyService and DockerEventManager
|
||||
// concurrently instead of waiting on a 5s blocking spawn here.
|
||||
try {
|
||||
execFileSync('docker', ['compose', 'version'], { stdio: 'pipe', timeout: 5000 });
|
||||
await execFileAsync('docker', ['compose', 'version'], { timeout: 5000 });
|
||||
} catch {
|
||||
console.log('[SelfUpdate] docker compose CLI not available in container');
|
||||
disableCapability('self-update');
|
||||
|
||||
Reference in New Issue
Block a user