fix: preserve follower timing at state write
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
import { execFileSync } from "node:child_process";
|
||||
|
||||
const namespace = process.env.NAMESPACE || "";
|
||||
const configMap = process.env.CONFIGMAP || "";
|
||||
const followerId = process.env.FOLLOWER_ID || "";
|
||||
|
||||
try {
|
||||
const raw = execFileSync("kubectl", ["-n", namespace, "get", "configmap", configMap, "-o", "json"], {
|
||||
encoding: "utf8",
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
});
|
||||
const data = JSON.parse(raw).data || {};
|
||||
process.stdout.write(data[followerId] || "{}");
|
||||
} catch {
|
||||
process.stdout.write("{}");
|
||||
}
|
||||
+46
-1
@@ -2399,7 +2399,8 @@ function roundSeconds(value: number): number {
|
||||
}
|
||||
|
||||
function writeFollowerState(registry: BranchFollowerRegistry, state: FollowerState, options: ParsedOptions): CommandResult {
|
||||
const json = JSON.stringify(compactFollowerStateForConfigMap(state));
|
||||
const stateForWrite = preserveWriteTimeTotalTiming(registry, state, options);
|
||||
const json = JSON.stringify(compactFollowerStateForConfigMap(stateForWrite));
|
||||
const dataPatch = JSON.stringify({ data: { [state.id]: json, _updatedAt: new Date().toISOString(), _specRef: SPEC_REF } });
|
||||
if (options.inCluster) {
|
||||
const patchBase64 = Buffer.from(dataPatch, "utf8").toString("base64");
|
||||
@@ -2464,6 +2465,50 @@ function writeFollowerState(registry: BranchFollowerRegistry, state: FollowerSta
|
||||
return runKubeScript(registry, options, script, "", 10_000);
|
||||
}
|
||||
|
||||
function preserveWriteTimeTotalTiming(registry: BranchFollowerRegistry, state: FollowerState, options: ParsedOptions): FollowerState {
|
||||
if (state.timings.totalSeconds !== null) return state;
|
||||
const existing = readExistingFollowerStateForWrite(registry, state.id, options);
|
||||
const existingTimings = asOptionalRecord(existing?.timings);
|
||||
if (existingTimings === null) return state;
|
||||
const sourceCommit = stringOrNull(existingTimings.sourceCommit);
|
||||
if (sourceCommit === null || sourceCommit !== state.source.observedSha) return state;
|
||||
const startedAt = stringOrNull(existingTimings.startedAt);
|
||||
const existingFinishedAt = stringOrNull(existingTimings.finishedAt);
|
||||
const finishedAt = existingFinishedAt ?? (terminalPhase(state.phase) ? new Date().toISOString() : null);
|
||||
const seconds = totalSecondsFromRange(startedAt, finishedAt) ?? numberOrNull(existingTimings.totalSeconds);
|
||||
if (seconds === null) return state;
|
||||
return {
|
||||
...state,
|
||||
timings: {
|
||||
...state.timings,
|
||||
totalSeconds: seconds,
|
||||
totalStatus: terminalPhase(state.phase) ? "completed" : state.phase.toLowerCase(),
|
||||
totalSource: stringOrNull(existingTimings.totalSource) ?? "stored-state",
|
||||
sourceCommit,
|
||||
startedAt,
|
||||
finishedAt,
|
||||
overBudget: seconds > state.timings.budgetSeconds,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function readExistingFollowerStateForWrite(registry: BranchFollowerRegistry, followerId: string, options: ParsedOptions): Record<string, unknown> | null {
|
||||
const script = [
|
||||
"set -eu",
|
||||
`NAMESPACE=${shQuote(registry.controller.namespace)}`,
|
||||
`CONFIGMAP=${shQuote(registry.controller.stateConfigMapName)}`,
|
||||
`FOLLOWER_ID=${shQuote(followerId)}`,
|
||||
"export NAMESPACE CONFIGMAP FOLLOWER_ID",
|
||||
"tmpdir=$(mktemp -d)",
|
||||
"cleanup() { rm -rf \"$tmpdir\"; }",
|
||||
"trap cleanup EXIT INT TERM",
|
||||
nativeCicdScriptLoadShell(["read-follower-state.mjs"]),
|
||||
"node \"$tmpdir/read-follower-state.mjs\"",
|
||||
].join("\n");
|
||||
const result = runKubeScript(registry, options, script, "", 10_000);
|
||||
return result.exitCode === 0 ? parseJsonObject(result.stdout) : null;
|
||||
}
|
||||
|
||||
function runControllerReconcileJob(registry: BranchFollowerRegistry, options: ParsedOptions, mode: { dryRun: boolean; wait: boolean; recordState: boolean }): Record<string, unknown> {
|
||||
const timeoutSeconds = options.timeoutSeconds ?? registry.controller.budgets.runOnceSeconds;
|
||||
const jobName = `${registry.controller.deploymentName}-once-${Date.now().toString(36)}`.slice(0, 63);
|
||||
|
||||
Reference in New Issue
Block a user