MCPcopy
hub / github.com/coder/mux / RuntimeBackgroundHandle

Class RuntimeBackgroundHandle

src/node/services/backgroundProcessExecutor.ts:216–337  ·  view source on GitHub ↗

* Unified handle to a background process. * Uses runtime.exec for all operations, working identically for local and SSH. * * Output files (output.log, exit_code) are on the runtime's filesystem. * This handle provides lifecycle management via execBuffered commands.

Source from the content-addressed store, hash-verified

214 * This handle provides lifecycle management via execBuffered commands.
215 */
216class RuntimeBackgroundHandle implements BackgroundHandle {
217 private terminated = false;
218
219 constructor(
220 private readonly runtime: Runtime,
221 private readonly pid: number,
222 public readonly outputDir: string,
223 private readonly quotePath: (p: string) => string
224 ) {}
225
226 /**
227 * Get the exit code from the exit_code file.
228 * Returns null if process is still running (file doesn't exist yet).
229 */
230 async getExitCode(): Promise<number | null> {
231 try {
232 const exitCodePath = this.quotePath(`${this.outputDir}/${EXIT_CODE_FILENAME}`);
233 const result = await execBuffered(
234 this.runtime,
235 `cat ${exitCodePath} 2>/dev/null || echo ""`,
236 { cwd: FALLBACK_CWD, timeout: 10 }
237 );
238 return parseExitCode(result.stdout);
239 } catch (error) {
240 log.debug(`RuntimeBackgroundHandle.getExitCode: Error: ${errorMsg(error)}`);
241 return null;
242 }
243 }
244
245 /**
246 * Terminate the process group.
247 * Sends SIGTERM to process group, waits briefly, then SIGKILL if still running.
248 */
249 async terminate(): Promise<void> {
250 if (this.terminated) return;
251
252 try {
253 const exitCodePath = `${this.outputDir}/${EXIT_CODE_FILENAME}`;
254 const terminateCmd = buildTerminateCommand(this.pid, exitCodePath, this.quotePath);
255 await execBuffered(this.runtime, terminateCmd, {
256 cwd: FALLBACK_CWD,
257 timeout: 15,
258 });
259 log.debug(`RuntimeBackgroundHandle: Terminated process group ${this.pid}`);
260 } catch (error) {
261 // Process may already be dead - that's fine
262 log.debug(`RuntimeBackgroundHandle.terminate: Error: ${errorMsg(error)}`);
263 }
264
265 this.terminated = true;
266 }
267
268 /**
269 * Clean up resources.
270 * No resources to clean - process runs independently via nohup.
271 */
272 async dispose(): Promise<void> {
273 // No resources to clean up

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected