From bf6e97c35ddb8a635710e1b04a4d5367913bf7fe Mon Sep 17 00:00:00 2001 From: Nawaz Dhandala Date: Thu, 6 Nov 2025 19:41:01 +0000 Subject: [PATCH] feat(exec): add executeCommandInheritStdio and use it for nginx config test - Add spawn and SpawnOptions imports and implement Execute.executeCommandInheritStdio that runs commands with inherited stdio, logs errors, and rejects on non-zero exit. - Update NginxConfigurator to run `nginx -t -c /etc/nginx/nginx.conf` via the new inherit-stdio helper before reloading nginx. --- Common/Server/Utils/Execute.ts | 47 +++++++++++++++++++++++++++++++- Nginx/Utils/NginxConfigurator.ts | 10 +++++-- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/Common/Server/Utils/Execute.ts b/Common/Server/Utils/Execute.ts index 419e4aaafd..5aea454b3d 100644 --- a/Common/Server/Utils/Execute.ts +++ b/Common/Server/Utils/Execute.ts @@ -1,5 +1,12 @@ import { PromiseRejectErrorFunction } from "../../Types/FunctionTypes"; -import { ExecException, ExecOptions, exec, execFile } from "node:child_process"; +import { + ExecException, + ExecOptions, + SpawnOptions, + exec, + execFile, + spawn, +} from "node:child_process"; import logger from "./Logger"; import CaptureSpan from "./Telemetry/CaptureSpan"; @@ -79,4 +86,42 @@ export default class Execute { }, ); } + + @CaptureSpan() + public static executeCommandInheritStdio(data: { + command: string; + args?: Array; + options?: SpawnOptions; + }): Promise { + return new Promise((resolve: VoidFunction, reject: PromiseRejectErrorFunction) => { + const spawnOptions: SpawnOptions = { + stdio: ["ignore", "inherit", "inherit"], + shell: false, + ...data.options, + }; + + const child = spawn(data.command, data.args ?? [], spawnOptions); + + child.on("error", (err: Error) => { + logger.error( + `Error executing command: ${data.command} ${(data.args ?? []).join(" ")}`, + ); + logger.error(err); + reject(err); + }); + + child.on("close", (code: number | null) => { + if (code === 0) { + resolve(); + return; + } + + const error: Error = new Error( + `Command failed: ${data.command} ${(data.args ?? []).join(" ")} (exit code ${code ?? "unknown"})`, + ); + logger.error(error); + reject(error); + }); + }); + } } diff --git a/Nginx/Utils/NginxConfigurator.ts b/Nginx/Utils/NginxConfigurator.ts index 0f6cbcaa77..f851552deb 100644 --- a/Nginx/Utils/NginxConfigurator.ts +++ b/Nginx/Utils/NginxConfigurator.ts @@ -89,8 +89,14 @@ export default class NginxConfigurator { } await this.ensureLogFiles(); - await Exec.executeCommand("nginx -t"); - await Exec.executeCommand("nginx -s reload"); + await Exec.executeCommandInheritStdio({ + command: "nginx", + args: ["-t", "-c", "/etc/nginx/nginx.conf"], + }); + await Exec.executeCommandInheritStdio({ + command: "nginx", + args: ["-s", "reload"], + }); logger.info( `[NginxConfigurator] Reloaded nginx after updating certificate for ${normalizedHost}.`, );