From 45b6ea5a29fc3ead93162edc58d1fc722469438c Mon Sep 17 00:00:00 2001 From: Roger Ng Date: Tue, 12 May 2026 18:08:37 +0000 Subject: [PATCH] Prevent panic in badger antispam follower --- storage/posix/antispam/badger.go | 4 ++- storage/posix/antispam/badger_test.go | 38 +++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/storage/posix/antispam/badger.go b/storage/posix/antispam/badger.go index c90651bec..fb6d9741b 100644 --- a/storage/posix/antispam/badger.go +++ b/storage/posix/antispam/badger.go @@ -407,7 +407,9 @@ func (f *follower) Follow(ctx context.Context, lr tessera.LogReader) { if err != errOutOfSync { slog.ErrorContext(ctx, "Failed to commit antispam population tx", slog.Any("error", err)) } - stop() + if stop != nil { + stop() + } next = nil continue } diff --git a/storage/posix/antispam/badger_test.go b/storage/posix/antispam/badger_test.go index ccbe25e29..a1bf8dbf0 100644 --- a/storage/posix/antispam/badger_test.go +++ b/storage/posix/antispam/badger_test.go @@ -212,6 +212,44 @@ func TestAntispamPushbackRecovers(t *testing.T) { } } +func TestAntispamFollowerErrorBeforeStream(t *testing.T) { + as, err := NewAntispam(t.Context(), t.TempDir(), AntispamOpts{}) + if err != nil { + t.Fatalf("NewAntispam: %v", err) + } + + fl, shutdown := testonly.NewTestLog(t, tessera.NewAppendOptions().WithCheckpointInterval(time.Second)) + defer func() { + if err := shutdown(t.Context()); err != nil { + t.Logf("shutdown: %v", err) + } + }() + + f := as.Follower(testBundleHasher) + + mockLR := &failingLogReader{ + LogReader: fl.LogReader, + } + + ctx, cancel := context.WithCancel(t.Context()) + defer cancel() + + go f.Follow(ctx, mockLR) + + // Wait for the ticker (1s) and some execution time. + time.Sleep(1500 * time.Millisecond) + + cancel() +} + +type failingLogReader struct { + tessera.LogReader +} + +func (f *failingLogReader) IntegratedSize(ctx context.Context) (uint64, error) { + return 0, fmt.Errorf("injected error") +} + func testIDHash(d []byte) []byte { r := sha256.Sum256(d) return r[:]