diff options
| author | Paul Buetow <paul@buetow.org> | 2026-05-03 21:08:03 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-05-03 21:08:03 +0300 |
| commit | f3bc88ce84c6d44a949f0caf89d771c90d5da080 (patch) | |
| tree | c298cc2c7428d30462bf985a5bac14e4be678898 | |
| parent | d7a25aaf44641efb7d57975b13413112bf9c9977 (diff) | |
Fix GC worker test synchronization for task a
| -rw-r--r-- | internal/service/gc.go | 21 | ||||
| -rw-r--r-- | internal/service/gc_test.go | 11 |
2 files changed, 29 insertions, 3 deletions
diff --git a/internal/service/gc.go b/internal/service/gc.go index f95b12a..ef206fa 100644 --- a/internal/service/gc.go +++ b/internal/service/gc.go @@ -21,6 +21,8 @@ type GCWorker struct { age time.Duration logger *slog.Logger ticker *time.Ticker + tickCh <-chan time.Time + runDoneCh chan struct{} stopCh chan struct{} stopOnce sync.Once wg sync.WaitGroup @@ -57,14 +59,19 @@ func (w *GCWorker) WithInterval(interval time.Duration) *GCWorker { // Start launches the GC goroutine. func (w *GCWorker) Start() { w.ctx, w.cancel = context.WithCancel(context.Background()) - w.ticker = time.NewTicker(w.interval) + tickCh := w.tickCh + if tickCh == nil { + w.ticker = time.NewTicker(w.interval) + tickCh = w.ticker.C + } w.wg.Add(1) go func() { defer w.wg.Done() for { select { - case <-w.ticker.C: + case <-tickCh: w.run(w.ctx) + w.notifyRunDone() case <-w.stopCh: return } @@ -129,6 +136,16 @@ func (w *GCWorker) run(ctx context.Context) { } } +func (w *GCWorker) notifyRunDone() { + if w.runDoneCh == nil { + return + } + select { + case w.runDoneCh <- struct{}{}: + default: + } +} + // RunOnce performs a single GC run synchronously. Useful for tests. func (w *GCWorker) RunOnce() error { if w.interval == 0 { diff --git a/internal/service/gc_test.go b/internal/service/gc_test.go index c2bf708..26a2160 100644 --- a/internal/service/gc_test.go +++ b/internal/service/gc_test.go @@ -89,8 +89,17 @@ func TestGCWorker_StartStop(t *testing.T) { logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelError})) w := NewGCWorker(store, &clock.MockClock{T: now}, tmpDir, 10*time.Millisecond, logger).WithAge(7 * 24 * time.Hour) + tickCh := make(chan time.Time, 1) + runDoneCh := make(chan struct{}, 1) + w.tickCh = tickCh + w.runDoneCh = runDoneCh w.Start() - time.Sleep(50 * time.Millisecond) + tickCh <- now + select { + case <-runDoneCh: + case <-time.After(time.Second): + t.Fatal("timed out waiting for gc run") + } w.Stop() if !called { |
