cacheable

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 15, 2025 License: MIT Imports: 7 Imported by: 0

README

Cacheable

Golang simplified implentation of the java spring cacheable annotation.

Installation

go get github.com/pedrofaria/cacheable

Usage

main.go

package main

import (
    "context"
    "log"

    "github.com/pedrofaria/cachable"
    "github.com/pedrofaria/cachable/driver/redisdb"
)

func main() {
    cacheNotification := cacheable.New[model.Notification](
		redisdb.New(redisConn, false),
		cacheable.WithKeyPrefix("notification:communication_type_id:"),
		cacheable.WithTtl(24*time.Hour),
	)
	defer cacheNotification.Close()

    repo := repository.NewNotificationRepository(dbConn)
    storage := service.NewCostumerNotificationStorage(repo, cacheNotification)

    ctx := context.Background()

    n, err := storage.FetchNotification(ctx, "2")
    if err != nil {
        log.Fatalf("failed during fetch notification: %s", err.Error())
    }
}

internal/service/storage.go

package service

import (
	"context"

	"github.com/pedrofaria/notifications/internal/model"
	"github.com/pedrofaria/cacheable"
)

type CostumerNotificationRepositorier interface {
	Fetch(ctx context.Context, id string) (*model.Notification, error)
}

type CostumerNotificationStorage struct {
	cache cacheable.Cacheler[model.Notification]
	repo  CostumerNotificationRepositorier
}

func NewCostumerNotificationStorage(repo CostumerNotificationRepositorier, cache cacheable.Cacheler[model.Notification]) *CostumerNotificationStorage {
	return &CostumerNotificationStorage{
		cache: cache,
		repo:  repo,
	}
}

func (s *CostumerNotificationStorage) FetchNotification(ctx context.Context, id string) (*model.Notification, error) {
    // Try to fetch from cache. If it's not present in cache, will call repo.Fetch and will store on cache.
	return s.cache.Load(ctx, id, func(ctx context.Context) (*model.Notification, error) {
		return s.repo.Fetch(ctx, id)
	})
}

Drivers

  • Redis
  • Ristretto (in memory)
Redis

https://github.com/pedrofaria/cacheable/tree/main/driver/redisdb

import "github.com/pedrofaria/cachable/driver/redisdb"

Example:

package main

import (
    "context"
    "log"

	"github.com/redis/go-redis/v9"
    "github.com/pedrofaria/cachable"
    "github.com/pedrofaria/cachable/driver/redisdb"
)

func main() {
	redisConn := redis.NewClusterClient(&redis.ClusterOptions{
		Addrs:          []string{"localhost:6379"},
		RouteByLatency: true,
		Username:       "default",
		Password:       "default",
	})

	cache := cacheable.New[model.Notification](
		redisdb.New(redisConn, false),
		cacheable.WithKeyPrefix("notification:communication_type_id:"),
		cacheable.WithTtl(24*time.Hour),
	)
	defer cache.Close()

	// ...
}
Ristretto

https://github.com/pedrofaria/cacheable/tree/main/driver/ristretto

Library: https://github.com/dgraph-io/ristretto

import "github.com/pedrofaria/cachable/driver/ristretto"

Example:

package main

import (
    "context"
    "log"

    "github.com/pedrofaria/cachable"
    "github.com/pedrofaria/cachable/driver/ristretto"
)

func main() {
	ristrettoCache, _ := ristretto.NewCache(&ristretto.Config[string, []byte]{
		NumCounters: 1e7,     // number of keys to track frequency of (10M).
		MaxCost:     1 << 30, // maximum cost of cache (1GB).
		BufferItems: 64,      // number of keys per Get buffer.
	})

	cache := cacheable.New[model.Notification](
		ristretto.New(ristrettoCache),
		cacheable.WithKeyPrefix("notification:communication_type_id:"),
		cacheable.WithTtl(10*time.Minute),
	)
	defer cache.Close()

	// ...
}

Serialization and Deserialization

  • JSON (default)
  • Binary
  • Message Pack

Benchmark results:

goos: darwin
goarch: arm64
pkg: github.com/pedrofaria/cacheable
cpu: Apple M2 Pro
Benchmark_Cacheable_Load_Binary-12     	  176868	      6866 ns/op	    6928 B/op	     156 allocs/op
Benchmark_Cacheable_Load_Json-12       	 2946112	     402.2 ns/op	     256 B/op	       7 allocs/op
Benchmark_Cacheable_Load_Msgpack-12    	 5881483	     203.1 ns/op	      88 B/op	       4 allocs/op
PASS
ok  	github.com/pedrofaria/cacheable	5.740s
Binary

https://github.com/pedrofaria/cacheable/tree/main/serder/binary

import "github.com/pedrofaria/cachable/serder/binary"

Example:

package main

import (
    "context"
    "log"

    "github.com/pedrofaria/cachable"
    "github.com/pedrofaria/cachable/driver/ristretto"
	"github.com/pedrofaria/cachable/serder/binary"
)

func main() {
	ristrettoCache, _ := ristretto.NewCache(&ristretto.Config[string, []byte]{
		NumCounters: 1e7,     // number of keys to track frequency of (10M).
		MaxCost:     1 << 30, // maximum cost of cache (1GB).
		BufferItems: 64,      // number of keys per Get buffer.
	})

	cache := cacheable.New[model.Notification](
		ristretto.New(ristrettoCache),
		cacheable.WithKeyPrefix("notification:communication_type_id:"),
		cacheable.WithTtl(10*time.Minute),
		cacheable.WithSerder(binary.New())
	)
	defer cache.Close()

	// ...
}

Message Pack

https://github.com/pedrofaria/cacheable/tree/main/serder/msgpack

import "github.com/pedrofaria/cachable/serder/msgpack"

Example:

package main

import (
    "context"
    "log"

    "github.com/pedrofaria/cachable"
    "github.com/pedrofaria/cachable/driver/ristretto"
	"github.com/pedrofaria/cachable/serder/msgpack"
)

func main() {
	ristrettoCache, _ := ristretto.NewCache(&ristretto.Config[string, []byte]{
		NumCounters: 1e7,     // number of keys to track frequency of (10M).
		MaxCost:     1 << 30, // maximum cost of cache (1GB).
		BufferItems: 64,      // number of keys per Get buffer.
	})

	cache := cacheable.New[model.Notification](
		ristretto.New(ristrettoCache),
		cacheable.WithKeyPrefix("notification:communication_type_id:"),
		cacheable.WithTtl(10*time.Minute),
		cacheable.WithSerder(msgpack.New())
	)
	defer cache.Close()

	// ...
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func New

func New[T any](driver driver.Driver, opts ...Option) *cacheable[T]

New creates a new cacheable instance with the given driver and options. It returns a pointer to a cacheable instance.

The driver parameter is required and will be used to store and retrieve cache entries. The opts parameter is optional and can be used to customize the cacheable instance.

Example:

cache := cachable.New[MyType](redisDriver,
	cachable.WithKeyPrefix("myapp:"),
	cachable.WithTTL(time.Hour),
)

Types

type Cacheler added in v0.0.2

type Cacheler[T any] interface {
	// Load method takes a context for handling cancellation and timeouts,
	// a key to identify the cached item, and a loadFn which is called when
	// the item is not found in the cache or needs to be refreshed.
	Load(ctx context.Context, key string, loadFn func(ctx context.Context) (*T, error)) (*T, error)

	Remove(ctx context.Context, key string) error

	GetStats() Stats
}

Cacheler is a generic interface for maintaining data in a cache. It defines a Load method that retrieves data from the cache if available, or calls loadFn to fetch and potentially store data otherwise.

type Option

type Option func(*config)

func WithIgnoreErr added in v0.0.4

func WithIgnoreErr(ignoreErr bool) Option

func WithKeyPrefix

func WithKeyPrefix(keyPrefix string) Option

func WithSerder

func WithSerder(serder serder.Serder) Option

func WithTtl

func WithTtl(defaultTtl time.Duration) Option

type Stats added in v0.0.5

type Stats struct {
	Hits       uint64
	Miss       uint64
	SetSuccess uint64
	SetError   uint64
	DelSuccess uint64
	DelError   uint64
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL