diff --git a/.yarn/changelogs/service.38497d1d.md b/.yarn/changelogs/service.38497d1d.md new file mode 100644 index 0000000..0946a88 --- /dev/null +++ b/.yarn/changelogs/service.38497d1d.md @@ -0,0 +1,48 @@ + +# service + + + +## โœจ Features + + +## ๐Ÿ› Bug Fixes + + +## ๐Ÿ“š Documentation + + +## โšก Performance + - Improved service startup performance with parallel REST API initialization and deferred stale process detection + +## โ™ป๏ธ Refactoring + + +## ๐Ÿงช Tests + + +## ๐Ÿ“ฆ Build + + +## ๐Ÿ‘ท CI + + +## โฌ†๏ธ Dependencies + + +## ๐Ÿ”ง Chores + diff --git a/.yarn/versions/38497d1d.yml b/.yarn/versions/38497d1d.yml new file mode 100644 index 0000000..16da3cb --- /dev/null +++ b/.yarn/versions/38497d1d.yml @@ -0,0 +1,5 @@ +releases: + service: patch + +declined: + - stack-craft diff --git a/service/src/service.ts b/service/src/service.ts index c23c1e2..d239e02 100644 --- a/service/src/service.ts +++ b/service/src/service.ts @@ -29,6 +29,16 @@ import { encryptExistingSecrets } from './utils/encrypt-existing-secrets.js' const host = getHost() const port = getPort() +const logStartupError = (scope: string, error: unknown): void => { + getLogger(injector) + .withScope(scope) + .error({ + message: `Background startup task failed: ${error instanceof Error ? error.message : String(error)}`, + data: { error }, + }) + .catch(() => console.error(`Background startup task failed (logger unavailable) [${scope}]`, error)) +} + const setupRestApis = async () => { await setupDataStore(injector) await setupLogStore(injector) @@ -36,21 +46,26 @@ const setupRestApis = async () => { injector.get(ExternalGitChangeListener).start() + // Stale-state cleanup and secret re-encryption don't gate REST availability โ€” run them + // in the background so HTTP can start accepting requests sooner. const processManager = injector.get(ProcessManager) - await processManager.reconcileStaleStates() + void processManager.reconcileStaleStates().catch((error) => logStartupError('StaleStateReconciler', error)) - await usingAsync(useSystemIdentityContext({ injector }), async (elevated) => { + void usingAsync(useSystemIdentityContext({ injector }), async (elevated) => { await encryptExistingSecrets(elevated) - }) + }).catch((error) => logStartupError('EncryptExistingSecrets', error)) - await setupInstallRestApi(injector) - await setupIdentityRestApi(injector) - await setupStacksRestApi(injector) - await setupServicesRestApi(injector) - await setupGitHubReposRestApi(injector) - await setupPrerequisitesRestApi(injector) - await setupTokensRestApi(injector) - await setupSystemRestApi(injector) + // Each module registers its own route group independently, so they can be set up concurrently. + await Promise.all([ + setupInstallRestApi(injector), + setupIdentityRestApi(injector), + setupStacksRestApi(injector), + setupServicesRestApi(injector), + setupGitHubReposRestApi(injector), + setupPrerequisitesRestApi(injector), + setupTokensRestApi(injector), + setupSystemRestApi(injector), + ]) const wsService = injector.get(WebsocketService) await wsService.init(injector)