Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | 15x 10x 5x 5x 5x 10x 3x 7x 3x 4x 3x 11x 9x 11x 9x 30x 2x 28x 28x 25x 8x 8x 7x 7x 18x 18x 3x 3x 31x 29x 29x 22x 22x 22x 22x 22x 22x 14x 22x 22x 22x | // execution-phases/cleanup-phase.ts
// Verantwortlichkeit: Cleanup nach Ausführung
// - Batchers flushen und stoppen
// - Message Queue leeren
// - Docker-Container cleanup
import type { Logger } from "@shared/logger";
import type { ProcessExecution } from "../../process-execution-port";
import type { ExecutionState } from "../execution-manager";
export interface CleanupDependencies {
processExecutor: ProcessExecution;
logger: Logger;
}
/**
* Flush die Message Queue und sendet alle queued Messages an Callbacks
*/
export function flushMessageQueue(state: ExecutionState): void {
if (state.messageQueue.length === 0) {
return;
}
const queue = state.messageQueue;
state.messageQueue = [];
for (const msg of queue) {
if (msg.type === "pinState" && state.pinStateCallback) {
state.pinStateCallback(msg.data.pin, msg.data.stateType, msg.data.value);
} else if (msg.type === "output" && state.onOutputCallback) {
state.onOutputCallback(msg.data.line, msg.data.isComplete);
} else if (msg.type === "error" && state.errorCallback) {
state.errorCallback(msg.data.line);
}
}
}
/**
* Stoppt Batchers (SerialOutputBatcher und PinStateBatcher)
*/
export function flushBatchers(state: ExecutionState): void {
if (state.serialOutputBatcher) {
state.serialOutputBatcher.stop();
}
if (state.pinStateBatcher) {
state.pinStateBatcher.stop();
}
}
/**
* Räumt Docker-Container auf
*/
export async function cleanupDockerContainer(
containerName: string | undefined,
deps: CleanupDependencies,
): Promise<boolean> {
if (!containerName) {
return true;
}
try {
const result = await deps.processExecutor.execute("docker", ["rm", "-f", containerName], {
timeout: 5000,
stdio: "pipe",
});
if (result.code !== 0 || result.error) {
// docker run uses --rm. A failed rm can mean auto-removal, but only a
// successful daemon listing can establish absence (not an error string).
// A name filter can conservatively match more than the exact name;
// an empty successful listing still proves this container is absent.
const remaining = await deps.processExecutor.execute("docker", [
"container", "ls", "--all", "--filter", `name=${containerName}`, "--quiet",
], { timeout: 5000, stdio: "pipe" });
if (remaining.code !== 0 || remaining.error || remaining.stdout?.trim() !== "") {
deps.logger.warn(`Docker cleanup failed for ${containerName} (code ${result.code})`);
return false;
}
}
deps.logger.info(`Docker container cleanup: ${containerName}`);
return true;
} catch (error) {
deps.logger.debug(`Docker cleanup failed for ${containerName}: ${error}`);
return false;
}
}
// Natural close, deadline and explicit Stop must join the same removal. The
// weak key retains no completed sessions; each runner owns at most one flight.
const cleanupFlights = new WeakMap<ExecutionState, { name: string; completion: Promise<void> }>();
export function cleanupExecutionContainer(state: ExecutionState, deps: CleanupDependencies): Promise<void> {
const name = state.currentContainerName;
if (!name) return Promise.resolve();
const pending = cleanupFlights.get(state);
Iif (pending?.name === name) return pending.completion;
const generation = state.runGeneration;
const flight = { name, completion: Promise.resolve() };
flight.completion = cleanupDockerContainer(name, deps).then((removed) => {
if (removed && state.runGeneration === generation && state.currentContainerName === name) {
state.currentContainerName = undefined;
}
}).finally(() => {
Eif (cleanupFlights.get(state) === flight) cleanupFlights.delete(state);
});
cleanupFlights.set(state, flight);
return flight.completion;
}
|