wracha

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Aug 10, 2023 License: MIT Imports: 9 Imported by: 1

README

WraCha

Easy wrapper for lazy caching results of an action for Go. Safe for multi-threaded/multi-instance use.

Supports in memory cache, go-redis, and redigo.

Installation

Simply run the following command to install:

go get github.com/pwnedgod/wracha

Usage

Initialization

To use, prepare a wracha.ActorOptions with your flavor of adapter, codec, and logger.

package main

import (
    "github.com/pwnedgod/wracha"
    "github.com/pwnedgod/wracha/adapter/memory"
    "github.com/pwnedgod/wracha/codec/json"
    "github.com/pwnedgod/wracha/logger/std"
)

func main() {
    opts := wracha.ActorOptions(
        memory.NewAdapter(),
        json.NewCodec(),
        std.NewLogger(),
    )

    // ...
}
Defining Action

Create an wracha.Actor through wracha.NewActor with the options.

The name given will be used as a prefix for cache key.

actor := wracha.NewActor[MyStruct]("example", opts)

// Set options...
actor.SetTTL(time.Duration(30) * time.Minute).
    SetPreActionErrorHandler(preActionErrorHandler).
    SetPostActionErrorHandler(postActionErrorHandler)

An action is defined as

func[T any](context.Context) (ActionResult[T], error)

The action must return a wracha.ActionResult[T any].

  • Cache determines whether to cache the given value.
  • TTL overrides the set TTL value.
  • Value is the value to return and possibly cache. Must be serializable.

If the action returns an error, the actor will not attempt to cache.

Performing The Action

To perform an action, call wracha.Actor[T any].Do.

The first parameter is the key of the given action. The actor will only attempt to retrieve previous values from cache of the same key. If such value is found in cache, the action will not be performed again.

wracha.Actor[T any].Do will return the value from wracha.ActionResult[T any] and error. The returned error can either be from the action or from the caching process.

// Obtain key from either HTTP request or somewhere else...
id := "ffffffff-ffff-ffff-ffff-ffffffffffff"

user, err := actor.Do(ctx, wracha.KeyableStr(id), func[model.User](ctx context.Context) (wracha.ActionResult[model.User], error) {
    user, err := userRepository.FindByID(ctx, id)
    if err != nil {
        return wracha.ActionResult[model.User]{}, err
    }

    // Some other actions...

    return wracha.ActionResult[model.User]{
        Cache: true,
        Value: user,
    }, nil
})

// Return value from action, write to response, etc...
Invalidating Dependency/Cache Entry

If a dependency/cache entry is stale, it can be invalidated and deleted off from cache using wracha.Actor[T any].Invalidate.

id := "ffffffff-ffff-ffff-ffff-ffffffffffff"

err := actor.Invalidate(ctx, wracha.KeyableStr(id))
if err != nil {
    // ...
}
Error Handling

By default, errors thrown before calling the action (value retrieval or locking) immediately executes the action without an attempt to store the value in cache. All errors thrown after calling the action (value storage) is also ignored.

You can override this behaviour by setting either wracha.Actor[T any].SetPreActionErrorHandler or wracha.Actor[T any].SetPostActionErrorHandler.

Multiple Dependencies

If multiple dependencies are required, you can wrap your dependencies with wracha.KeyableMap. The map will be converted to a hashed SHA1 representation as key for the cache.

deps := wracha.KeyableMap{
    "roleId": "123456abc",
    "naming": "roger*",
}

res, err := actor.Do(ctx, deps, /* ... */)
Adapters

Adapters are used for storing cache data. Out of the box, three adapters are provided:

  • memory (uses ccache)
  • goredis
  • redigo

You can create your own adapter by satisfying the following interface:

type Adapter interface {
	Exists(ctx context.Context, key string) (bool, error)
	Get(ctx context.Context, key string) ([]byte, error)
	Set(ctx context.Context, key string, ttl time.Duration, data []byte) error
	Delete(ctx context.Context, key string) error
	Lock(ctx context.Context, key string) error
	Unlock(ctx context.Context, key string) error
}

go-redis
client := redis.NewClient(&redis.Options{
    // ...
})

opts := wracha.ActorOptions{
    goredis.NewAdapter(client),
    // ...
}
redigo
pool := &redis.Pool{
    // ...
}

opts := wracha.ActorOptions{
    redigo.NewAdapter(pool),
    // ...
}
Codec

Codecs are used for serializing the value for storage in cache. Currently only JSON and msgpack are provided.

Keep in mind these serializations are not perfect, especially for time.Time.

Documentation

Index

Constants

View Source
const (
	TTLDefault = time.Duration(10) * time.Minute
)

Variables

This section is empty.

Functions

func DefaultPostActionErrorHandler

func DefaultPostActionErrorHandler[T any](ctx context.Context, args PostActionErrorHandlerArgs[T]) (T, error)

func DefaultPreActionErrorHandler

func DefaultPreActionErrorHandler[T any](ctx context.Context, args PreActionErrorHandlerArgs[T]) (T, error)

Types

type ActionFunc

type ActionFunc[T any] func(ctx context.Context) (ActionResult[T], error)

type ActionResult

type ActionResult[T any] struct {
	// Whether to cache the returned values.
	Cache bool

	// The TTL of the cached values. If set to zero, defaults to the actor settings.
	TTL time.Duration

	// The values to cache and return.
	Value T
}

type Actor

type Actor[T any] interface {
	// Set default TTL of cache.
	SetTTL(ttl time.Duration) Actor[T]

	// Set error handler for handling unconventional errors thrown before action (get in cache and lock).
	//
	// Value and error returned by the handler will be forwarded as a return value for Actor.Do.
	SetPreActionErrorHandler(handler PreActionErrorHandlerFunc[T]) Actor[T]

	// Set error handler for handling unconventional errors thrown after action (store).
	//
	// Value and error returned by the handler will be forwarded as a return value for Actor.Do.
	SetPostActionErrorHandler(handler PostActionErrorHandlerFunc[T]) Actor[T]

	// Invalidate the value of the given key.
	Invalidate(ctx context.Context, key Keyable) error

	// Perform an action.
	// The action will not be executed again if the key exists in cache.
	Do(ctx context.Context, key Keyable, action ActionFunc[T]) (T, error)
}

func NewActor added in v0.2.0

func NewActor[T any](name string, options ActorOptions) Actor[T]

type ActorOptions added in v0.2.0

type ActorOptions struct {
	Adapter adapter.Adapter
	Codec   codec.Codec
	Logger  logger.Logger
}

type Keyable

type Keyable interface {
	Key() (string, error)
}

type KeyableMap

type KeyableMap map[string]any

func (KeyableMap) Key

func (m KeyableMap) Key() (string, error)

type KeyableStr added in v0.2.0

type KeyableStr string

func (KeyableStr) Key added in v0.2.0

func (m KeyableStr) Key() (string, error)

type PostActionErrorHandlerArgs

type PostActionErrorHandlerArgs[T any] struct {
	Key         Keyable
	Action      ActionFunc[T]
	Result      ActionResult[T]
	ErrCategory string
	Err         error
}

type PostActionErrorHandlerFunc

type PostActionErrorHandlerFunc[T any] func(ctx context.Context, args PostActionErrorHandlerArgs[T]) (T, error)

type PreActionErrorHandlerArgs

type PreActionErrorHandlerArgs[T any] struct {
	Key         Keyable
	Action      ActionFunc[T]
	ErrCategory string
	Err         error
}

type PreActionErrorHandlerFunc

type PreActionErrorHandlerFunc[T any] func(ctx context.Context, args PreActionErrorHandlerArgs[T]) (T, error)

Directories

Path Synopsis
std

Jump to

Keyboard shortcuts

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