Merge pull request #1522 from pikasTech/fix/1519-agentrun-closeout-scheduling
fix: prioritize branch follower closeout scheduling
This commit is contained in:
@@ -35,6 +35,7 @@ import { runBranchFollowerTaskRunDrillDown } from "./cicd-taskrun-drilldown";
|
|||||||
import { runBranchFollowerJobDrillDown, runBranchFollowerRuntimeDrillDown } from "./cicd-job-runtime-drilldown";
|
import { runBranchFollowerJobDrillDown, runBranchFollowerRuntimeDrillDown } from "./cicd-job-runtime-drilldown";
|
||||||
import { runBranchFollowerGate } from "./cicd-gates";
|
import { runBranchFollowerGate } from "./cicd-gates";
|
||||||
import { attachReconcileTimeline, compactReconcileTimeline, finishReconcileStep, finishReconcileTimeline, startReconcileStep, startReconcileTimeline } from "./cicd-reconcile-timeline";
|
import { attachReconcileTimeline, compactReconcileTimeline, finishReconcileStep, finishReconcileTimeline, startReconcileStep, startReconcileTimeline } from "./cicd-reconcile-timeline";
|
||||||
|
import { orderFollowersForControllerCloseout, shouldYieldAfterAutomaticTrigger } from "./cicd-reconcile-scheduler";
|
||||||
import type { AdapterSummary, BranchFollowerAction, BranchFollowerDebugStep, BranchFollowerGate, BranchFollowerPhase, BranchFollowerRegistry, ControllerSpec, FollowerSpec, FollowerState, K8sFollowerStateRead, K8sStateRead, NativeCloseoutWaitResult, NativeK8sJobResult, NativeStatusSpec, NativeWorkloadSpec, OutputMode, ParsedOptions, StageTiming, TriggerResult } from "./cicd-types";
|
import type { AdapterSummary, BranchFollowerAction, BranchFollowerDebugStep, BranchFollowerGate, BranchFollowerPhase, BranchFollowerRegistry, ControllerSpec, FollowerSpec, FollowerState, K8sFollowerStateRead, K8sStateRead, NativeCloseoutWaitResult, NativeK8sJobResult, NativeStatusSpec, NativeWorkloadSpec, OutputMode, ParsedOptions, StageTiming, TriggerResult } from "./cicd-types";
|
||||||
import {
|
import {
|
||||||
arrayField,
|
arrayField,
|
||||||
@@ -707,10 +708,13 @@ async function runOnce(registry: BranchFollowerRegistry, options: ParsedOptions)
|
|||||||
const stateReadStep = startReconcileStep(reconcileTimeline, "*", "state-read");
|
const stateReadStep = startReconcileStep(reconcileTimeline, "*", "state-read");
|
||||||
const previous = readK8sState(registry, options);
|
const previous = readK8sState(registry, options);
|
||||||
finishReconcileStep(stateReadStep, { status: previous.ok ? "ok" : "degraded", object: registry.controller.stateConfigMapName, reason: previous.errors.join("; ") });
|
finishReconcileStep(stateReadStep, { status: previous.ok ? "ok" : "degraded", object: registry.controller.stateConfigMapName, reason: previous.errors.join("; ") });
|
||||||
|
const scheduled = orderFollowersForControllerCloseout(selected, previous.stateByFollower);
|
||||||
|
reconcileTimeline.followerCount = scheduled.length;
|
||||||
|
reconcileTimeline.followers = scheduled.map((follower) => follower.id).slice(0, 8);
|
||||||
const results: FollowerState[] = [];
|
const results: FollowerState[] = [];
|
||||||
const stateWriteWarnings: string[] = [];
|
const stateWriteWarnings: string[] = [];
|
||||||
const stateWrites: Record<string, unknown>[] = [];
|
const stateWrites: Record<string, unknown>[] = [];
|
||||||
for (const follower of selected) {
|
for (const follower of scheduled) {
|
||||||
const oldState = previous.stateByFollower[follower.id] ?? {};
|
const oldState = previous.stateByFollower[follower.id] ?? {};
|
||||||
const statusReadStep = startReconcileStep(reconcileTimeline, follower.id, "status-read");
|
const statusReadStep = startReconcileStep(reconcileTimeline, follower.id, "status-read");
|
||||||
const live = await readAdapterStatus(registry, follower, options);
|
const live = await readAdapterStatus(registry, follower, options);
|
||||||
@@ -732,6 +736,10 @@ async function runOnce(registry: BranchFollowerRegistry, options: ParsedOptions)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
results.push(state);
|
results.push(state);
|
||||||
|
if (shouldYieldAfterAutomaticTrigger(options, state)) {
|
||||||
|
stateWriteWarnings.push(`controller yielded after triggering ${follower.id}; remaining followers will be reconciled by the next loop`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
finishReconcileTimeline(reconcileTimeline);
|
finishReconcileTimeline(reconcileTimeline);
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
// SPEC: PJ2026-01060703 CI/CD branch follower controller scheduling.
|
||||||
|
// Responsibility: keep automatic closeout observations ahead of unrelated followers.
|
||||||
|
|
||||||
|
import type { FollowerSpec, FollowerState, ParsedOptions } from "./cicd-types";
|
||||||
|
|
||||||
|
const CLOSEOUT_PHASES = new Set(["Triggering", "ClosingOut"]);
|
||||||
|
|
||||||
|
export function orderFollowersForControllerCloseout(
|
||||||
|
followers: FollowerSpec[],
|
||||||
|
stateByFollower: Record<string, Record<string, unknown>>,
|
||||||
|
): FollowerSpec[] {
|
||||||
|
return followers
|
||||||
|
.map((follower, index) => ({ follower, index, priority: followerPriority(stateByFollower[follower.id]) }))
|
||||||
|
.sort((left, right) => left.priority - right.priority || left.index - right.index)
|
||||||
|
.map((item) => item.follower);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function shouldYieldAfterAutomaticTrigger(options: ParsedOptions, state: FollowerState): boolean {
|
||||||
|
if (!options.inCluster || !options.confirm || options.wait || options.dryRun) return false;
|
||||||
|
return state.phase === "Triggering" && state.inFlightJob !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function followerPriority(state: Record<string, unknown> | undefined): number {
|
||||||
|
if (state === undefined) return 2;
|
||||||
|
const phase = typeof state.phase === "string" ? state.phase : null;
|
||||||
|
if (phase !== null && CLOSEOUT_PHASES.has(phase)) return 0;
|
||||||
|
if (typeof state.inFlightJob === "string" && state.inFlightJob.trim() !== "") return 0;
|
||||||
|
if (phase === "PendingTrigger" || phase === "Superseded") return 1;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user