Skip to content

Commit

Permalink
[-] updated README to add ServeStale as a key feature
Browse files Browse the repository at this point in the history
[-] updated README with a full example
  • Loading branch information
bnkamalesh committed Oct 8, 2024
1 parent 24e08c9 commit 63eacd0
Showing 1 changed file with 93 additions and 1 deletion.
94 changes: 93 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ Pocache (`poh-cash (/poʊ kæʃ/)`), **P**reemptive **O**ptimistic Cache, is a l

1. **Preemptive Cache Updates:** Automatically updates cache entries nearing expiration.
2. **Threshold Window:** Configurable time window before cache expiration to trigger updates.
3. **Debounced Updates:** Prevents excessive I/O calls by debouncing concurrent requests for the same key.
3. **Serve stale**: Opt-in configuration to serve even expired cache and do a background refresh.
4. **Debounced Updates:** Prevents excessive I/O calls by debouncing concurrent requests for the same key.

## How does it work?

Expand All @@ -37,6 +38,97 @@ In highly concurrent environments (e.g., web servers), multiple requests might t

Additionally by debouncing these requests, Pocache ensures only a single update is triggered, reducing load on both the underlying storage and the application itself.

## Full example

```golang
package main

import (
"context"
"fmt"
"time"

"github.com/naughtygopher/pocache"
)

type Item struct {
ID string
Name string
Description string
}

func newItem(key string) *Item {
return &Item{
ID: fmt.Sprintf("%d", time.Now().Nanosecond()),
Name: "name::" + key,
Description: "description::" + key,
}
}

func updater(ctx context.Context, key string) (*Item, error) {
return newItem(key), nil
}

func onErr(err error) {
panic(fmt.Sprintf("this should never have happened!: %+v", err))
}

func main() {
cache, err := pocache.New(pocache.Config[string, *Item]{
// LRUCacheSize is the number of keys to be maintained in the cache (Optional, default 1000)
LRUCacheSize: 100000,
// QLength is the length of update and delete queue (Optional, default 1000)
QLength: 1000,

// CacheAge is for how long the cache would be maintained, apart from the LRU eviction
// It's maintained to not maintain stale data if/when keys are not evicted based on LRU
// (Optional, default 1minute)
CacheAge: time.Hour,
// Threshold is the duration prior to expiry, when the key is considered eligible to be updated
// (Optional, default 1 second)
Threshold: time.Minute * 5,

// ServeStale will not return error if the cache has expired. It will return the stale
// value, and trigger an update as well. This is useful for usecases where it's ok
// to serve stale values and data consistency is not of paramount importance.
// (Optional, default false)
ServeStale: false,

// UpdaterTimeout is the context time out for when the updater function is called
// (Optional, default 1 second)
UpdaterTimeout: time.Second * 15,
// Updater is optional, but without it it's a basic LRU cache
Updater: updater,

// ErrWatcher is called when there's any error when trying to update cache (Optional)
ErrWatcher: onErr,
})
if err != nil {
panic(err)
}

const key = "hello"
item := newItem(key)
e := cache.Add(key, item)
fmt.Println("evicted:", e)

ee := cache.BulkAdd([]pocache.Tuple[string, *Item]{
{Key: key + "2", Value: newItem(key + "2")},
})
fmt.Println("evicted list:", ee)

ii := cache.Get(key)
if ii.Found {
fmt.Println("value:", ii.V)
}

ii = cache.Get(key + "2")
if ii.Found {
fmt.Println("value:", ii.V)
}
}
```

## The gopher

The gopher used here was created using [Gopherize.me](https://gopherize.me/). Incache helps you keep your application latency low and your database destressed.

0 comments on commit 63eacd0

Please sign in to comment.