Skip to content

Commit 266241a

Browse files
Thomas StrombergThomas Stromberg
authored andcommitted
Add SetAsync method
1 parent 20309fb commit 266241a

File tree

6 files changed

+564
-22
lines changed

6 files changed

+564
-22
lines changed

.golangci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ linters:
186186
arguments: [10]
187187
- name: flag-parameter # fixes are difficult
188188
disabled: true
189+
- name: confusing-naming # false positives
190+
disabled: true
189191

190192
rowserrcheck:
191193
# database/sql is always checked.

README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,8 @@ cache, err := bdcache.New[string, int](ctx)
2424
if err != nil {
2525
return err
2626
}
27-
if err := cache.Set(ctx, "answer", 42, 0); err != nil {
28-
return err
29-
}
27+
cache.Set(ctx, "answer", 42, 0) // Synchronous: returns after persistence completes
28+
cache.SetAsync(ctx, "answer", 42, 0) // Async: returns immediately, persists in background
3029
val, found, err := cache.Get(ctx, "answer")
3130

3231
// With smart persistence (local files for dev, Google Cloud Datastore for Cloud Run)

cache.go

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,40 @@ func (c *Cache[K, V]) Set(ctx context.Context, key K, value V, ttl time.Duration
171171
return nil
172172
}
173173

174+
// SetAsync adds or updates a value in the cache with optional TTL, handling persistence asynchronously.
175+
// Key validation and in-memory caching happen synchronously. Persistence errors are logged but not returned.
176+
// Returns an error only for validation failures (e.g., invalid key format).
177+
func (c *Cache[K, V]) SetAsync(ctx context.Context, key K, value V, ttl time.Duration) error {
178+
var expiry time.Time
179+
if ttl > 0 {
180+
expiry = time.Now().Add(ttl)
181+
} else if c.opts.DefaultTTL > 0 {
182+
expiry = time.Now().Add(c.opts.DefaultTTL)
183+
}
184+
185+
// Validate key early if persistence is enabled (synchronous)
186+
if c.persist != nil {
187+
if err := c.persist.ValidateKey(key); err != nil {
188+
return err
189+
}
190+
}
191+
192+
// ALWAYS update memory first - reliability guarantee (synchronous)
193+
c.memory.setToMemory(key, value, expiry)
194+
195+
// Update persistence asynchronously if available
196+
if c.persist != nil {
197+
go func() {
198+
if err := c.persist.Store(ctx, key, value, expiry); err != nil {
199+
slog.Warn("async persistence store failed", "error", err, "key", key)
200+
}
201+
}()
202+
}
203+
204+
return nil
205+
}
206+
174207
// Delete removes a value from the cache.
175-
//
176-
//nolint:revive // confusing-naming - standard cache operation
177208
func (c *Cache[K, V]) Delete(ctx context.Context, key K) {
178209
// Remove from memory
179210
c.memory.deleteFromMemory(key)
@@ -194,8 +225,6 @@ func (c *Cache[K, V]) Delete(ctx context.Context, key K) {
194225

195226
// Cleanup removes expired entries from the cache.
196227
// Returns the number of entries removed.
197-
//
198-
//nolint:revive // confusing-naming - standard cache operation
199228
func (c *Cache[K, V]) Cleanup() int {
200229
return c.memory.cleanupMemory()
201230
}
@@ -206,8 +235,6 @@ func (c *Cache[K, V]) Len() int {
206235
}
207236

208237
// Close releases resources held by the cache.
209-
//
210-
//nolint:revive // confusing-naming - standard cache operation
211238
func (c *Cache[K, V]) Close() error {
212239
if c.persist != nil {
213240
if err := c.persist.Close(); err != nil {

0 commit comments

Comments
 (0)