MCPcopy Create free account
hub / github.com/tiann/hapi / startRunner

Function startRunner

cli/src/runner/run.ts:30–1087  ·  view source on GitHub ↗
(options: { workspaceRoots?: string[] } = {})

Source from the content-addressed store, hash-verified

28import { scheduleCursorModelsPrewarm } from '@/modules/common/cursorModelsPrewarm';
29
30export async function startRunner(options: { workspaceRoots?: string[] } = {}): Promise<void> {
31 // We don't have cleanup function at the time of server construction
32 // Control flow is:
33 // 1. Create promise that will resolve when shutdown is requested
34 // 2. Setup signal handlers to resolve this promise with the source of the shutdown
35 // 3. Once our setup is complete - if all goes well - we await this promise
36 // 4. When it resolves we can cleanup and exit
37 //
38 // In case the setup malfunctions - our signal handlers will not properly
39 // shut down. We will force exit the process with code 1.
40 let requestShutdown: (source: 'hapi-app' | 'hapi-cli' | 'os-signal' | 'exception', errorMessage?: string) => void;
41 let resolvesWhenShutdownRequested = new Promise<({ source: 'hapi-app' | 'hapi-cli' | 'os-signal' | 'exception', errorMessage?: string })>((resolve) => {
42 requestShutdown = (source, errorMessage) => {
43 logger.debug(`[RUNNER RUN] Requesting shutdown (source: ${source}, errorMessage: ${errorMessage})`);
44
45 // Fallback - in case startup malfunctions - we will force exit the process with code 1
46 setTimeout(async () => {
47 logger.debug('[RUNNER RUN] Startup malfunctioned, forcing exit with code 1');
48
49 // Give time for logs to be flushed
50 await new Promise(resolve => setTimeout(resolve, 100))
51
52 process.exit(1);
53 }, 1_000);
54
55 // Start graceful shutdown
56 resolve({ source, errorMessage });
57 };
58 });
59
60 // Setup signal handlers
61 process.on('SIGINT', () => {
62 logger.debug('[RUNNER RUN] Received SIGINT');
63 requestShutdown('os-signal');
64 });
65
66 process.on('SIGTERM', () => {
67 logger.debug('[RUNNER RUN] Received SIGTERM');
68 requestShutdown('os-signal');
69 });
70
71 if (isWindows()) {
72 process.on('SIGBREAK', () => {
73 logger.debug('[RUNNER RUN] Received SIGBREAK');
74 requestShutdown('os-signal');
75 });
76 }
77
78 process.on('uncaughtException', (error) => {
79 logger.debug('[RUNNER RUN] FATAL: Uncaught exception', error);
80 logger.debug(`[RUNNER RUN] Stack trace: ${error.stack}`);
81 requestShutdown('exception', error.message);
82 });
83
84 process.on('unhandledRejection', (reason, promise) => {
85 logger.debug('[RUNNER RUN] FATAL: Unhandled promise rejection', reason);
86 logger.debug(`[RUNNER RUN] Rejected promise:`, promise);
87 const error = reason instanceof Error ? reason : new Error(`Unhandled promise rejection: ${reason}`);

Callers 1

runner.tsFile · 0.90

Calls 15

isWindowsFunction · 0.90
getEnvironmentInfoFunction · 0.90
readRunnerStateFunction · 0.90
isProcessAliveFunction · 0.90
stopRunnerFunction · 0.90
acquireRunnerLockFunction · 0.90
startRunnerControlServerFunction · 0.90
getInstalledCliMtimeMsFunction · 0.90
getCliArgsFunction · 0.90
hashRunnerCliApiTokenFunction · 0.90

Tested by

no test coverage detected