Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions lib/builds/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -1127,7 +1127,11 @@ func (m *manager) StreamBuildEvents(ctx context.Context, id string, follow bool)
if !follow || isComplete {
return
}
// Wait for log file to appear, or for build to complete
// Wait for log file to appear, or for build to complete.
// Send heartbeats while waiting so SSE connections survive
// infrastructure idle timeouts (e.g. load balancer 60s timeout).
waitHeartbeat := time.NewTicker(15 * time.Second)
defer waitHeartbeat.Stop()
for {
select {
case <-ctx.Done():
Expand All @@ -1138,11 +1142,16 @@ func (m *manager) StreamBuildEvents(ctx context.Context, id string, follow bool)
case <-ctx.Done():
return
}
// Check if build completed
if event.Status == StatusReady || event.Status == StatusFailed || event.Status == StatusCancelled {
return
}
// Non-terminal status event - keep waiting for log file
continue
case <-waitHeartbeat.C:
select {
case out <- BuildEvent{Type: EventTypeHeartbeat, Timestamp: time.Now()}:
case <-ctx.Done():
return
}
Comment on lines +1150 to +1154
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inner select seems redundant relative to the outer but nbd

continue
case <-time.After(500 * time.Millisecond):
if _, err := os.Stat(logPath); err == nil {
Expand All @@ -1152,6 +1161,7 @@ func (m *manager) StreamBuildEvents(ctx context.Context, id string, follow bool)
}
break
}
waitHeartbeat.Stop()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't need? ✂️

}

// Build tail command args
Expand Down
Loading