Skip to content

Commit 911f06e

Browse files
Fix startup time calculation for restarted containers (#317)
For is_restart=true records, calculate time_to_ready_ms from running_at instead of pending_at. pending_at is the pod's original creation time and never resets across container restarts, causing crashlooping pods to report wildly inflated startup times (e.g. 318 hours instead of 19 seconds). This fixes the root cause identified in services PR #7552, allowing the CASE/helper workarounds there to be removed. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 6e8b635 commit 911f06e

1 file changed

Lines changed: 32 additions & 14 deletions

File tree

internal/collector/pod_collector.go

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -602,13 +602,22 @@ func (c *PodCollector) trackStartupLifecycle(_, newPod *corev1.Pod) {
602602
if newStatus.Ready && entry.runningAt != nil {
603603
// Calculate durations
604604
var timeToRunningMs, timeToReadyMs *int64
605-
if entry.pendingAt != nil && entry.runningAt != nil {
606-
ms := entry.runningAt.Sub(*entry.pendingAt).Milliseconds()
607-
timeToRunningMs = &ms
608-
}
609-
if entry.pendingAt != nil {
610-
ms := now.Sub(*entry.pendingAt).Milliseconds()
611-
timeToReadyMs = &ms
605+
if entry.isRestart {
606+
// For restarts, pendingAt is the pod's original creation time (never resets),
607+
// so measure from runningAt to get the actual per-restart duration.
608+
if entry.runningAt != nil {
609+
ms := now.Sub(*entry.runningAt).Milliseconds()
610+
timeToReadyMs = &ms
611+
}
612+
} else {
613+
if entry.pendingAt != nil && entry.runningAt != nil {
614+
ms := entry.runningAt.Sub(*entry.pendingAt).Milliseconds()
615+
timeToRunningMs = &ms
616+
}
617+
if entry.pendingAt != nil {
618+
ms := now.Sub(*entry.pendingAt).Milliseconds()
619+
timeToReadyMs = &ms
620+
}
612621
}
613622

614623
c.emitStartupLifecycleEvent(entry, &now, timeToRunningMs, timeToReadyMs)
@@ -729,14 +738,23 @@ func (c *PodCollector) snapshotStartupLifecycles(pod *corev1.Pod) {
729738

730739
var timeToRunningMs, timeToReadyMs *int64
731740

732-
ms := runningAt.Sub(pendingAt).Milliseconds()
733-
if ms > 0 {
734-
timeToRunningMs = &ms
735-
}
741+
if entry.isRestart {
742+
// For restarts, pendingAt is the pod's original creation time (never resets),
743+
// so measure from runningAt to get the actual per-restart duration.
744+
ms := readyAt.Sub(runningAt).Milliseconds()
745+
if ms > 0 {
746+
timeToReadyMs = &ms
747+
}
748+
} else {
749+
ms := runningAt.Sub(pendingAt).Milliseconds()
750+
if ms > 0 {
751+
timeToRunningMs = &ms
752+
}
736753

737-
ms = readyAt.Sub(pendingAt).Milliseconds()
738-
if ms > 0 {
739-
timeToReadyMs = &ms
754+
ms = readyAt.Sub(pendingAt).Milliseconds()
755+
if ms > 0 {
756+
timeToReadyMs = &ms
757+
}
740758
}
741759

742760
c.emitStartupLifecycleEvent(entry, readyAt, timeToRunningMs, timeToReadyMs)

0 commit comments

Comments
 (0)