Skip to content

Commit fcebcc3

Browse files
Thomas StrombergThomas Stromberg
authored andcommitted
Don't bother with error channels, nobody is going to use them
1 parent 5a992dd commit fcebcc3

File tree

2 files changed

+18
-34
lines changed

2 files changed

+18
-34
lines changed

persistent.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package bdcache
33
import (
44
"context"
55
"fmt"
6+
"log/slog"
67
"time"
78
)
89

@@ -181,9 +182,9 @@ func (c *PersistentCache[K, V]) Set(ctx context.Context, key K, value V, ttl ...
181182
// SetAsync stores a value in the cache, handling persistence asynchronously.
182183
// If no TTL is provided, the default TTL is used.
183184
// Key validation and in-memory caching happen synchronously.
184-
// Returns a channel that will receive any persistence error (or be closed on success).
185+
// Persistence errors are logged but not returned (fire-and-forget).
185186
// Returns an error only for validation failures (e.g., invalid key format).
186-
func (c *PersistentCache[K, V]) SetAsync(ctx context.Context, key K, value V, ttl ...time.Duration) (<-chan error, error) {
187+
func (c *PersistentCache[K, V]) SetAsync(ctx context.Context, key K, value V, ttl ...time.Duration) error {
187188
var t time.Duration
188189
if len(ttl) > 0 {
189190
t = ttl[0]
@@ -192,24 +193,23 @@ func (c *PersistentCache[K, V]) SetAsync(ctx context.Context, key K, value V, tt
192193

193194
// Validate key early (synchronous)
194195
if err := c.Store.ValidateKey(key); err != nil {
195-
return nil, err
196+
return err
196197
}
197198

198199
// ALWAYS update memory first - reliability guarantee (synchronous)
199200
c.memory.setToMemory(key, value, timeToNano(expiry))
200201

201-
// Update persistence asynchronously
202-
errCh := make(chan error, 1)
202+
// Update persistence asynchronously (fire-and-forget)
203+
//nolint:contextcheck // Intentionally detached - persistence should complete even if caller cancels
203204
go func() {
204-
defer close(errCh)
205-
storeCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
205+
storeCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
206206
defer cancel()
207207
if err := c.Store.Store(storeCtx, key, value, expiry); err != nil {
208-
errCh <- fmt.Errorf("async persistence: %w", err)
208+
slog.Error("async persistence failed", "key", key, "error", err)
209209
}
210210
}()
211211

212-
return errCh, nil
212+
return nil
213213
}
214214

215215
// Delete removes a value from the cache.

persistent_test.go

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -303,8 +303,7 @@ func TestPersistentCache_SetAsync(t *testing.T) {
303303
defer func() { _ = cache.Close() }() //nolint:errcheck // Test cleanup
304304

305305
// SetAsync should not block but value should be available immediately
306-
errCh, err := cache.SetAsync(ctx, "key1", 42, 0)
307-
if err != nil {
306+
if err := cache.SetAsync(ctx, "key1", 42, 0); err != nil {
308307
t.Fatalf("SetAsync: %v", err)
309308
}
310309

@@ -317,10 +316,8 @@ func TestPersistentCache_SetAsync(t *testing.T) {
317316
t.Error("key1 should be available immediately after SetAsync")
318317
}
319318

320-
// Wait for async persistence to complete
321-
if err := <-errCh; err != nil {
322-
t.Fatalf("SetAsync persistence: %v", err)
323-
}
319+
// Give async persistence time to complete
320+
time.Sleep(50 * time.Millisecond)
324321

325322
// Should also be persisted
326323
val, _, found, err = store.Load(ctx, "key1")
@@ -377,10 +374,9 @@ func TestPersistentCache_Errors(t *testing.T) {
377374
t.Error("key1 should be in memory even though persistence failed")
378375
}
379376

380-
// SetAsync returns error channel for persistence errors
377+
// SetAsync logs persistence errors but doesn't return them
381378
store.failSet = true
382-
errCh, err := cache.SetAsync(ctx, "key3", 300, 0)
383-
if err != nil {
379+
if err := cache.SetAsync(ctx, "key3", 300, 0); err != nil {
384380
t.Fatalf("SetAsync should not fail synchronously: %v", err)
385381
}
386382

@@ -393,10 +389,8 @@ func TestPersistentCache_Errors(t *testing.T) {
393389
t.Error("key3 should be in memory after SetAsync")
394390
}
395391

396-
// Persistence error should come through the channel
397-
if err := <-errCh; err == nil {
398-
t.Error("SetAsync should report persistence error through channel")
399-
}
392+
// Give async persistence time to attempt (and fail with logged error)
393+
time.Sleep(50 * time.Millisecond)
400394

401395
// Get should work from memory even if persistence fails
402396
store.failGet = true
@@ -868,25 +862,15 @@ func TestPersistentCache_SetAsync_VariadicTTL(t *testing.T) {
868862
defer func() { _ = cache.Close() }() //nolint:errcheck // Test cleanup
869863

870864
// SetAsync without TTL - uses default
871-
errCh1, err := cache.SetAsync(ctx, "async-default", 1)
872-
if err != nil {
865+
if err := cache.SetAsync(ctx, "async-default", 1); err != nil {
873866
t.Fatalf("SetAsync: %v", err)
874867
}
875868

876869
// SetAsync with explicit TTL
877-
errCh2, err := cache.SetAsync(ctx, "async-explicit", 2, 5*time.Minute)
878-
if err != nil {
870+
if err := cache.SetAsync(ctx, "async-explicit", 2, 5*time.Minute); err != nil {
879871
t.Fatalf("SetAsync: %v", err)
880872
}
881873

882-
// Wait for persistence
883-
if err := <-errCh1; err != nil {
884-
t.Fatalf("SetAsync persistence: %v", err)
885-
}
886-
if err := <-errCh2; err != nil {
887-
t.Fatalf("SetAsync persistence: %v", err)
888-
}
889-
890874
// Both should be in memory immediately
891875
_, found, err := cache.Get(ctx, "async-default")
892876
if err != nil {

0 commit comments

Comments
 (0)