🌳
pt0/deployF/k8sF/awaitJobPodAI.mts
7type AwaitJobPodProps = WithClusterName & {
9 podName: string
10 containerName: string
11 timeoutMs?: number
12 skipHeader?: boolean
15export const defaultJobTimeoutMs = 40 * 60 * 1000 // kaniko build budget (single source); activeDeadlineSeconds derives from this
17// Returns {failed, failReason} on job failure — caller owns failure diagnostics
18// (single shared OOM/log checker in epKubeJobKanikoF.getFailedContainerLogs)
19export const awaitJobPod = async ({job, podName, containerName, cluster_name, timeoutMs = defaultJobTimeoutMs, skipHeader}: AwaitJobPodProps): Promise<{failed: true, failReason?: string} | undefined> => {
20 const pollInterval = 10_000
21 let elapsed = 0
23 const checkJob = async () => {
24 const j = await read2Resource({resource: job, cluster_name}) as {status?: {succeeded?: boolean, conditions?: {type: string, reason?: string}[]}}
25 if (j?.status?.succeeded) return {done: true}
26 const failed = j?.status?.conditions?.find(c => c.type === 'Failed')
27 if (failed) return {done: true, failed: true, failReason: failed.reason}
28 return {done: false}
29 }
31 if (!skipHeader) console.log(`streaming ${podName}/${containerName} logs...`)
32 eptKubeCli([cluster_name, 'logs', podName, '-c', containerName, '-f', '--timestamps'])
34 while (elapsed < timeoutMs) {
35 await sleep(pollInterval)
36 elapsed += pollInterval
37 const {done, failed, failReason} = await checkJob()
38 if (done) {
39 if (failed) return {failed: true, failReason}
40 return
41 }
42 }
43 throwDebugH({podName, timeoutMs, reason: 'timeout'})