1import { BatchV1Api, type V1Job } from '@kubernetes/client-node' 7const listActiveKanikoJobs = async ({batchApi, cluster_name}: {batchApi: BatchV1Api, cluster_name: string}): Promise<V1Job[]> => { 8 const {items: jobs} = await batchApi.listNamespacedJob({namespace: 'default', labelSelector: `cluster_name=${cluster_name}`}) 9 return jobs.filter(j => !!j.metadata?.name?.startsWith('kaniko2-') && !j.status?.succeeded && !j.status?.failed) 12export const serializeKanikoBuilds = async ({newJob, cluster_name, git_sha, logStatus}: { 13 newJob: V1Job, cluster_name: string, git_sha: string, logStatus: (status: string) => void, 15 const jobName = newJob.metadata?.name 17 const rntIdx = jobName.lastIndexOf('-rnt-') 18 const appPrefix = rntIdx === -1 ? jobName : jobName.slice(0, rntIdx + 5) 20 const batchApi = kubeConfig.makeApiClient(BatchV1Api) 21 const activeA = await listActiveKanikoJobs({batchApi, cluster_name}) 22 const staleSameAppA = activeA.filter(j => { 23 const jName = j.metadata?.name 24 return !!jName && jName !== jobName && jName.startsWith(appPrefix) && j.metadata?.labels?.git_sha !== git_sha 26 for (const j of staleSameAppA) { 27 const staleJobName = j.metadata!.name! 28 logStatus(`canceling superseded ${staleJobName}`) 29 await batchApi.deleteNamespacedJob({name: staleJobName, namespace: 'default', propagationPolicy: 'Background'}) 31 const otherNamesA = activeA.filter(j => { 32 const jName = j.metadata?.name 33 return !!jName && jName !== jobName && !jName.startsWith(appPrefix) && j.metadata?.labels?.git_sha !== git_sha 34 }).map(j => j.metadata!.name!) 35 if (!otherNamesA.length) return 36 const waitDeadlineMs = Date.now() + defaultJobTimeoutMs 37 let remainingA = otherNamesA 38 while (remainingA.length && Date.now() < waitDeadlineMs) { 39 logStatus(`waiting for ${remainingA.length} kaniko build(s)`) 41 const activeNowA = await listActiveKanikoJobs({batchApi, cluster_name}) 42 const activeNamesS = new Set(activeNowA.map(j => j.metadata?.name)) 43 remainingA = remainingA.filter(n => activeNamesS.has(n)) 45 // fail-open: proceed despite active builds — RWX PVC backstop prevents hard failure 46 if (remainingA.length) console.log(`proceeding despite ${remainingA.length} active kaniko build(s) (wait timeout)`)