Keep the daemon responsive during Git queue pressure (#3945)

* fix(server): keep Git pressure from stalling daemon

Git process starts were refilled synchronously, so slow process spawning could monopolize the main loop long enough to trip connection liveness checks. Admit one process per event-loop turn and expose refresh/fetch provenance in runtime queue metrics.

* perf(server): avoid delaying isolated Git commands

Start the first command immediately when the scheduler is idle. Backlog admission and completion-driven refills still yield between spawns, preserving daemon liveness without adding a turn to normal sequential Git traffic.

* fix(server): keep Git admission outside fake clocks

Subprocess admission is event-loop ordering rather than simulated wall-clock behavior. Use the native Node immediate so service tests can fake debounce timers without deadlocking queued real Git processes.

* refactor(server): bind Git command provenance explicitly

* test(server): expect bound Git fetch runner
This commit is contained in:
Mohamed Boudra
2026-08-28 10:25:20 +02:00
committed by GitHub
parent fe803f6e70
commit fb67d2cdc8
12 changed files with 429 additions and 122 deletions
+14 -2
View File
@@ -62,6 +62,15 @@ export interface GitCommandResult {
signal: NodeJS.Signals | null;
}
export type RunGitCommand = (
args: string[],
options: GitCommandOptions,
) => Promise<GitCommandResult>;
export function createRunGitCommand(provenance: string): RunGitCommand {
return (args, options) => runGitCommandWithProvenance(args, options, provenance);
}
export interface GitCommandMetric {
args: string[];
cwd: string;
@@ -249,16 +258,17 @@ function getEnvOverlayKeys(envOverlay: ProcessEnvRecord | undefined): string[] {
return Object.keys(envOverlay ?? {}).sort();
}
export function runGitCommand(
function runGitCommandWithProvenance(
args: string[],
options: GitCommandOptions,
provenance?: string,
): Promise<GitCommandResult> {
const metricsState = submitGitCommandMetric(args, options.cwd);
const commandTrace = submitGitCommandTrace(args, options.cwd, {
active: gitProcessScheduler.activeCount,
pending: gitProcessScheduler.pendingCount,
});
const runtimeMetric = gitRuntimeMetrics.submit(getGitOperation(args));
const runtimeMetric = gitRuntimeMetrics.submit(getGitOperation(args), provenance);
const startCommand = () => {
let releaseProcessSlot!: () => void;
const exited = new Promise<void>((resolve) => {
@@ -526,6 +536,8 @@ export function runGitCommand(
return promise;
}
export const runGitCommand: RunGitCommand = runGitCommandWithProvenance;
function formatGitCommand(args: string[]): string {
return ["git", ...args].join(" ");
}