rueidisaside

package
v1.0.25 Latest Latest
Warning

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

Go to latest
Published: Dec 22, 2023 License: Apache-2.0 Imports: 7 Imported by: 0

README

rueidisaside

A Cache-Aside pattern implementation enhanced by Client Side Caching.

Features backed by the Redis Client Side Caching

Cache-Aside is a widely used pattern to cache other data sources into Redis. However, there are many issues to be considered when implementing it.

For example, an implementation without locking or versioning may cause a fresh cache be overridden by a stale one. And if using a locking mechanism, how to get notified when a lock is released? If using versioning mechanism, how to version an empty value?

Thankfully, the above issues can be addressed better with the client-side caching along with the following additional benefits:

  • Avoiding unnecessary network round trips. Redis will proactively invalidate the client-side cache.
  • Avoiding Cache Stampede by locking keys with the client-side caching, the same technique used in rueidislock. Only the first cache missed call can update the cache and others will wait for notifications.

Example

package main

import (
	"context"
	"database/sql"
	"time"

	"github.com/redis/rueidis"
	"github.com/redis/rueidis/rueidisaside"
)

func main() {
	var db sql.DB
	client, err := rueidisaside.NewClient(rueidisaside.ClientOption{
		ClientOption: rueidis.ClientOption{InitAddress: []string{"127.0.0.1:6379"}},
	})
	if err != nil {
		panic(err)
	}
	val, err := client.Get(context.Background(), time.Minute, "mykey", func(ctx context.Context, key string) (val string, err error) {
		if err = db.QueryRowContext(ctx, "SELECT val FROM mytab WHERE id = ?", key).Scan(&val); err == sql.ErrNoRows {
			val = "_nil_" // cache nil to avoid penetration.
			err = nil     // clear err in case of sql.ErrNoRows.
		}
		return
	})
	if err != nil {
		panic(err)
	} else if val == "_nil_" {
		val = ""
		err = sql.ErrNoRows
	} else {
		// ...
	}
}

Limitation

Currently, requires Redis >= 7.0.

Documentation

Index

Constants

View Source
const PlaceholderPrefix = "rueidisid:"

Variables

This section is empty.

Functions

This section is empty.

Types

type CacheAsideClient

type CacheAsideClient interface {
	Get(ctx context.Context, ttl time.Duration, key string, fn func(ctx context.Context, key string) (val string, err error)) (val string, err error)
	Del(ctx context.Context, key string) error
	Client() rueidis.Client
	Close()
}

func NewClient

func NewClient(option ClientOption) (cc CacheAsideClient, err error)

type Client

type Client struct {
	// contains filtered or unexported fields
}

func (*Client) Client

func (c *Client) Client() rueidis.Client

Client exports the underlying rueidis.Client

func (*Client) Close

func (c *Client) Close()

func (*Client) Del

func (c *Client) Del(ctx context.Context, key string) error

func (*Client) Get

func (c *Client) Get(ctx context.Context, ttl time.Duration, key string, fn func(ctx context.Context, key string) (val string, err error)) (string, error)

type ClientOption

type ClientOption struct {
	// ClientBuilder can be used to modify rueidis.Client used by Locker
	ClientBuilder func(option rueidis.ClientOption) (rueidis.Client, error)
	ClientOption  rueidis.ClientOption
	ClientTTL     time.Duration // TTL for the client marker, refreshed every 1/2 TTL. Defaults to 10s. The marker allows other client to know if this client is still alive.
}

Jump to

Keyboard shortcuts

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