detached fced651

fix: resolve readiness probe lint issues

Replace the log stream cancellation marker with explicit stopped state so
lint no longer flags an uncancelled context, and drop the unused readiness
endpoint wrapper left behind by the probe refactor.
commit
fced65178c906feadc58c401bfa83407a43f1386
author
brice · · 2026-03-12 19:09 UTC
parent
50a9fab
signature
unsigned
2 files · +7 -13
M internal/adapters/out/logwriter/logwriter.go +7 -9
@@ -8,6 +8,7 @@ import (
88 "path/filepath"
99 "strings"
1010 "sync"
11+ "sync/atomic"
1112
1213 "github.com/bnema/zerowrap"
1314 "github.com/docker/docker/pkg/stdcopy"
@@ -39,7 +40,7 @@ type streamInfo struct {
3940 domain string
4041 logStream io.ReadCloser
4142 logger *lumberjack.Logger
42- cancel context.CancelFunc
43+ stopped atomic.Bool
4344 done chan struct{}
4445 }
4546
@@ -89,8 +90,6 @@ func (w *LogWriter) StartLogging(ctx context.Context, containerID string, domain
8990 Compress: true,
9091 }
9192
92- // Create cancellable context for the streaming goroutine
93- streamCtx, cancel := context.WithCancel(context.Background())
9493 done := make(chan struct{})
9594
9695 info := &streamInfo{
@@ -98,14 +97,13 @@ func (w *LogWriter) StartLogging(ctx context.Context, containerID string, domain
9897 domain: domain,
9998 logStream: logStream,
10099 logger: logger,
101- cancel: cancel,
102100 done: done,
103101 }
104102
105103 w.streams[containerID] = info
106104
107105 // Start streaming goroutine
108- go w.streamLogs(streamCtx, info, log)
106+ go w.streamLogs(info, log)
109107
110108 log.Info().Str("path", logPath).Msg("started container log collection")
111109 return nil
@@ -138,7 +136,7 @@ func (w *LogWriter) Close() error {
138136 // stopStreamLocked stops a stream (must be called with lock held).
139137 func (w *LogWriter) stopStreamLocked(info *streamInfo) {
140138 // Signal the goroutine to stop
141- info.cancel()
139+ info.stopped.Store(true)
142140
143141 // Close the log stream to unblock reads
144142 info.logStream.Close()
@@ -151,7 +149,7 @@ func (w *LogWriter) stopStreamLocked(info *streamInfo) {
151149 }
152150
153151 // streamLogs copies from the Docker log stream to the file.
154-func (w *LogWriter) streamLogs(ctx context.Context, info *streamInfo, log zerowrap.Logger) {
152+func (w *LogWriter) streamLogs(info *streamInfo, log zerowrap.Logger) {
155153 defer close(info.done)
156154
157155 // Docker container logs are multiplexed with 8-byte headers.
@@ -159,8 +157,8 @@ func (w *LogWriter) streamLogs(ctx context.Context, info *streamInfo, log zerowr
159157 // We combine both to a single file.
160158 _, err := stdcopy.StdCopy(info.logger, info.logger, info.logStream)
161159
162- if err != nil && ctx.Err() == nil {
163- // Only log error if we weren't cancelled
160+ if err != nil && !info.stopped.Load() {
161+ // Only log error if we weren't intentionally stopped
164162 log.Warn().Err(err).
165163 Str("container_id", info.containerID).
166164 Str("domain", info.domain).
@@ -8,6 +8,7 @@ import (
8 "path/filepath"8 "path/filepath"
9 "strings"9 "strings"
10 "sync"10 "sync"
11+ "sync/atomic"
11 12
12 "github.com/bnema/zerowrap"13 "github.com/bnema/zerowrap"
13 "github.com/docker/docker/pkg/stdcopy"14 "github.com/docker/docker/pkg/stdcopy"
@@ -39,7 +40,7 @@ type streamInfo struct {
39 domain string40 domain string
40 logStream io.ReadCloser41 logStream io.ReadCloser
41 logger *lumberjack.Logger42 logger *lumberjack.Logger
42- cancel context.CancelFunc43+ stopped atomic.Bool
43 done chan struct{}44 done chan struct{}
44 }45 }
45 46
@@ -89,8 +90,6 @@ func (w *LogWriter) StartLogging(ctx context.Context, containerID string, domain
89 Compress: true,90 Compress: true,
90 }91 }
91 92
92- // Create cancellable context for the streaming goroutine
93- streamCtx, cancel := context.WithCancel(context.Background())
94 done := make(chan struct{})93 done := make(chan struct{})
95 94
96 info := &streamInfo{95 info := &streamInfo{
@@ -98,14 +97,13 @@ func (w *LogWriter) StartLogging(ctx context.Context, containerID string, domain
98 domain: domain,97 domain: domain,
99 logStream: logStream,98 logStream: logStream,
100 logger: logger,99 logger: logger,
101- cancel: cancel,
102 done: done,100 done: done,
103 }101 }
104 102
105 w.streams[containerID] = info103 w.streams[containerID] = info
106 104
107 // Start streaming goroutine105 // Start streaming goroutine
108- go w.streamLogs(streamCtx, info, log)106+ go w.streamLogs(info, log)
109 107
110 log.Info().Str("path", logPath).Msg("started container log collection")108 log.Info().Str("path", logPath).Msg("started container log collection")
111 return nil109 return nil
@@ -138,7 +136,7 @@ func (w *LogWriter) Close() error {
138 // stopStreamLocked stops a stream (must be called with lock held).136 // stopStreamLocked stops a stream (must be called with lock held).
139 func (w *LogWriter) stopStreamLocked(info *streamInfo) {137 func (w *LogWriter) stopStreamLocked(info *streamInfo) {
140 // Signal the goroutine to stop138 // Signal the goroutine to stop
141- info.cancel()139+ info.stopped.Store(true)
142 140
143 // Close the log stream to unblock reads141 // Close the log stream to unblock reads
144 info.logStream.Close()142 info.logStream.Close()
@@ -151,7 +149,7 @@ func (w *LogWriter) stopStreamLocked(info *streamInfo) {
151 }149 }
152 150
153 // streamLogs copies from the Docker log stream to the file.151 // streamLogs copies from the Docker log stream to the file.
154-func (w *LogWriter) streamLogs(ctx context.Context, info *streamInfo, log zerowrap.Logger) {152+func (w *LogWriter) streamLogs(info *streamInfo, log zerowrap.Logger) {
155 defer close(info.done)153 defer close(info.done)
156 154
157 // Docker container logs are multiplexed with 8-byte headers.155 // Docker container logs are multiplexed with 8-byte headers.
@@ -159,8 +157,8 @@ func (w *LogWriter) streamLogs(ctx context.Context, info *streamInfo, log zerowr
159 // We combine both to a single file.157 // We combine both to a single file.
160 _, err := stdcopy.StdCopy(info.logger, info.logger, info.logStream)158 _, err := stdcopy.StdCopy(info.logger, info.logger, info.logStream)
161 159
162- if err != nil && ctx.Err() == nil {160+ if err != nil && !info.stopped.Load() {
163- // Only log error if we weren't cancelled161+ // Only log error if we weren't intentionally stopped
164 log.Warn().Err(err).162 log.Warn().Err(err).
165 Str("container_id", info.containerID).163 Str("container_id", info.containerID).
166 Str("domain", info.domain).164 Str("domain", info.domain).
M internal/usecase/container/service.go +0 -4
@@ -2455,10 +2455,6 @@ func (s *Service) resolveProbeEndpoint(ctx context.Context, containerID string,
24552455 return ip, internalPort, nil
24562456 }
24572457
2458-func (s *Service) resolveContainerEndpoint(ctx context.Context, containerID string) (string, int, error) {
2459- return s.resolveProbeEndpoint(ctx, containerID, nil)
2460-}
2461-
24622458 // waitForReadyByDelay waits using the legacy running+delay strategy.
24632459 func (s *Service) waitForReadyByDelay(ctx context.Context, containerID string) error {
24642460 log := zerowrap.FromCtx(ctx)
@@ -2455,10 +2455,6 @@ func (s *Service) resolveProbeEndpoint(ctx context.Context, containerID string,
2455 return ip, internalPort, nil2455 return ip, internalPort, nil
2456 }2456 }
2457 2457
2458-func (s *Service) resolveContainerEndpoint(ctx context.Context, containerID string) (string, int, error) {
2459- return s.resolveProbeEndpoint(ctx, containerID, nil)
2460-}
2461-
2462 // waitForReadyByDelay waits using the legacy running+delay strategy.2458 // waitForReadyByDelay waits using the legacy running+delay strategy.
2463 func (s *Service) waitForReadyByDelay(ctx context.Context, containerID string) error {2459 func (s *Service) waitForReadyByDelay(ctx context.Context, containerID string) error {
2464 log := zerowrap.FromCtx(ctx)2460 log := zerowrap.FromCtx(ctx)

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close