diff --git a/internal/link/builds_nats.go b/internal/link/builds_nats.go index c3b1011..21bdca4 100644 --- a/internal/link/builds_nats.go +++ b/internal/link/builds_nats.go @@ -193,9 +193,15 @@ func (m *natsMachine) Take(ctx context.Context, do func(context.Context, Build)) // machine with nothing to build, and is asked again. fetched, err := sub.Fetch(1, nats.Context(ctx)) switch { - case errors.Is(err, context.Canceled), errors.Is(err, context.DeadlineExceeded): + case ctx.Err() != nil: + // Ours ended: the machine is being stopped. return nil - case errors.Is(err, nats.ErrTimeout): + case errors.Is(err, context.Canceled), errors.Is(err, context.DeadlineExceeded), errors.Is(err, nats.ErrTimeout): + // **An empty queue, not the end.** A fetch on a context without a deadline waits the + // client's own while and then says the deadline passed — the client's, not ours. Read + // as "stop", every idle build machine exited clean every half minute and was started + // again by its supervisor, which looked like a crash loop with nothing in the log to + // say why (2026-10-03, the first build agents). Asked again. continue case err != nil: if sub.IsValid() {