Skip to content

Commit

Permalink
feat: Add log options (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
viccon authored May 26, 2024
1 parent ad4aaf5 commit 3bc44ff
Show file tree
Hide file tree
Showing 8 changed files with 43 additions and 18 deletions.
14 changes: 7 additions & 7 deletions buffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ func bufferBatchRefresh[T any](c *Client[T], ids []string, keyFn KeyFn, fetchFn
c.batchMutex.Unlock()

// These IDs are the size we want, so we'll refresh them immediately.
safeGo(func() {
c.safeGo(func() {
c.refreshBatch(idsToRefresh, keyFn, fetchFn)
})

// We'll continue to process the remaining IDs recursively.
safeGo(func() {
c.safeGo(func() {
bufferBatchRefresh(c, overflowingIDs, keyFn, fetchFn)
})

Expand All @@ -55,7 +55,7 @@ func bufferBatchRefresh[T any](c *Client[T], ids []string, keyFn KeyFn, fetchFn
case channel <- ids:
stop()
case <-timer:
safeGo(func() {
c.safeGo(func() {
bufferBatchRefresh(c, ids, keyFn, fetchFn)
})
return
Expand All @@ -70,7 +70,7 @@ func bufferBatchRefresh[T any](c *Client[T], ids []string, keyFn KeyFn, fetchFn
c.bufferPermutationIDs[permutationString] = ids
c.batchMutex.Unlock()

safeGo(func() {
c.safeGo(func() {
timer, stop := c.clock.NewTimer(c.bufferTimeout)

for {
Expand All @@ -87,7 +87,7 @@ func bufferBatchRefresh[T any](c *Client[T], ids []string, keyFn KeyFn, fetchFn
deleteBuffer(c, permutationString)
c.batchMutex.Unlock()

safeGo(func() {
c.safeGo(func() {
c.refreshBatch(permIDs, keyFn, fetchFn)
})
return
Expand Down Expand Up @@ -121,13 +121,13 @@ func bufferBatchRefresh[T any](c *Client[T], ids []string, keyFn KeyFn, fetchFn
overflowingIDs := permIDs[c.bufferSize:]

// Refresh the first batch of IDs immediately.
safeGo(func() {
c.safeGo(func() {
c.refreshBatch(idsToRefresh, keyFn, fetchFn)
})

// If we exceeded the batch size, we'll continue to process the remaining IDs recursively.
if len(overflowingIDs) > 0 {
safeGo(func() {
c.safeGo(func() {
bufferBatchRefresh(c, overflowingIDs, keyFn, fetchFn)
})
}
Expand Down
3 changes: 3 additions & 0 deletions cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package sturdyc

import (
"context"
"log/slog"
"sync"
"time"

Expand Down Expand Up @@ -36,6 +37,7 @@ type Config struct {
clock Clock
evictionInterval time.Duration
metricsRecorder MetricsRecorder
log Logger

refreshInBackground bool
minRefreshTime time.Duration
Expand Down Expand Up @@ -84,6 +86,7 @@ func New[T any](capacity, numShards int, ttl time.Duration, evictionPercentage i
clock: NewClock(),
evictionInterval: ttl / time.Duration(numShards),
getSize: client.Size,
log: slog.Default(),
}
// Apply the options to the configuration.
client.Config = cfg
Expand Down
4 changes: 2 additions & 2 deletions fetch.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func (c *Client[T]) GetFetch(ctx context.Context, key string, fetchFn FetchFn[T]
value, ok, shouldIgnore, shouldRefresh := c.get(key)

if shouldRefresh {
safeGo(func() {
c.safeGo(func() {
c.refresh(key, fetchFn)
})
}
Expand Down Expand Up @@ -74,7 +74,7 @@ func (c *Client[T]) GetFetchBatch(ctx context.Context, ids []string, keyFn KeyFn

// If any records need to be refreshed, we'll do so in the background.
if len(idsToRefresh) > 0 {
safeGo(func() {
c.safeGo(func() {
if c.bufferRefreshes {
bufferBatchRefresh(c, idsToRefresh, keyFn, fetchFn)
return
Expand Down
11 changes: 8 additions & 3 deletions keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,20 @@ func (c *Client[T]) handleStruct(permutationStruct interface{}) string {
}

if v.Kind() != reflect.Struct {
panic("val must be a struct")
panic("permutationStruct must be a struct")
}

for i := 0; i < v.NumField(); i++ {
field := v.Field(i)

// Check if the field is exported
// Skip unexported fields
if !field.CanInterface() {
continue // Skip unexported fields
message := fmt.Sprintf(
"sturdyc: permutationStruct contains unexported field: %s which won't be part of the cache key",
v.Type().Field(i).Name,
)
c.log.Warn(message)
continue
}

if i > 0 {
Expand Down
11 changes: 11 additions & 0 deletions log.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package sturdyc

type Logger interface {
Warn(msg string, args ...any)
Error(msg string, args ...any)
}

type NoopLogger struct{}

func (l *NoopLogger) Warn(_ string, _ ...any) {}
func (l *NoopLogger) Error(_ string, _ ...any) {}
9 changes: 9 additions & 0 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,15 @@ func WithRelativeTimeKeyFormat(truncation time.Duration) Option {
}
}

// WithLog allows you to set a custom logger for the cache. The cache isn't chatty,
// and will only log warnings and errors that would be a nightmare to debug. If you
// absolutely don't want any logs, you can pass in the sturydc.NoopLogger.
func WithLog(log Logger) Option {
return func(c *Config) {
c.log = log
}
}

// validateConfig is a helper function that panics if the cache has been configured incorrectly.
func validateConfig(capacity, numShards int, ttl time.Duration, evictionPercentage int, cfg *Config) {
if capacity <= 0 {
Expand Down
9 changes: 3 additions & 6 deletions safe.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,16 @@ package sturdyc

import (
"context"
"log/slog"
"fmt"
)

// safeGo is a helper that prevents panics in any of the goroutines
// that are running in the background from crashing the process.
func safeGo(fn func()) {
func (c *Client[T]) safeGo(fn func()) {
go func() {
defer func() {
if err := recover(); err != nil {
// If we ever reach here it's because one of the functions that the user
// passed us panicked. I don't think packages should log like this, but
// failing silently here would make it an absolute nightmare to debug.
slog.Error("panic recovered: %v", err)
c.log.Error(fmt.Sprintf("sturdyc: panic recovered: %v", err))
}
}()
fn()
Expand Down
File renamed without changes.

0 comments on commit 3bc44ff

Please sign in to comment.