Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .github/workflows/coverage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
go: ['1.18', 'stable']
go: ['1.21', 'stable'] # 1.21 is the module floor (context.WithoutCancel)
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5

- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: ${{ matrix.go }}
cache: false # zero-dependency module: no go.sum for the cache key

- name: Build
run: go build ./...
Expand Down
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,22 @@ go get github.com/mbrostami/lastcache/v2

### stale-if-error (`Get` / `GetStale`)
When a fetch fails and a previous value is still around, the cache serves that
stale value for up to `Config.StaleTTL` instead of returning the error.
stale value instead of returning the error — for at most `Config.StaleTTL`
past expiry. The cap is a hard wall-clock bound anchored at the last
*successful* fetch: failed refreshes never extend it.

### stale-while-revalidate (`GetAsync`)
An expired value is returned immediately while a single background goroutine
refreshes it.

### negative caching (`NotFound` + `NegativeTTL`)
An error your `NotFound` classifier reports as an authoritative "does not
exist" evicts any cached value — a deleted key is never served stale — and is
itself cached for `NegativeTTL`, so a hammered missing key is answered from
cache instead of hitting the upstream. Keep `NegativeTTL` short: a negative
entry makes a key that was just created upstream look missing until it
expires.

## Usage

```go
Expand Down Expand Up @@ -88,8 +98,11 @@ type Result[V any] struct {
| Field | Meaning |
|-------|---------|
| `TTL` | How long a fetched value stays fresh. Defaults to 1 minute. |
| `StaleTTL` | How long a stale value may be served after expiry when a refresh fails. `0` disables serving stale. |
| `StaleTTL` | How long a stale value may be served after expiry when a refresh fails. A hard cap anchored at the last successful fetch; past it the value is treated as gone. `0` disables serving stale on error. |
| `MaxConcurrentRefresh` | Caps concurrent background refreshes (`GetAsync`) across all keys. Defaults to `1`. |
| `Capacity` | Bounds the number of entries; dead entries are evicted first, then arbitrary ones. `<= 0` means unbounded. Set it whenever keys come from user input. |
| `NotFound` | Optional `func(err error) bool` classifying a fetch error as an authoritative "does not exist". Such misses evict any cached value and are negatively cached. Nil treats every error as transient. |
| `NegativeTTL` | How long an authoritative miss is served from cache before re-fetching. `0` disables negative caching (misses still evict). |
| `OnError` | Optional `func(key any, err error)` called when a background refresh fails. |
| `Context` | Base context for background refreshes (they outlive the request). Defaults to `context.Background()`. |

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module github.com/mbrostami/lastcache/v2

go 1.18
go 1.21
Loading