Documentation
¶
Overview ¶
Package cache will supply caching solutions for your crud port compatible resources.
Index ¶
- Constants
- type Cache
- func (m *Cache[ENT, ID]) CachedQueryMany(ctx context.Context, hitID HitID, query QueryManyFunc[ENT]) (_ iter.Seq2[ENT, error], rErr error)
- func (m *Cache[ENT, ID]) CachedQueryOne(ctx context.Context, hitID HitID, query QueryOneFunc[ENT]) (_ent ENT, _found bool, _err error)
- func (m *Cache[ENT, ID]) Close() (rErr error)
- func (m *Cache[ENT, ID]) Create(ctx context.Context, ptr *ENT) error
- func (m *Cache[ENT, ID]) DeleteAll(ctx context.Context) error
- func (m *Cache[ENT, ID]) DeleteByID(ctx context.Context, id ID) (rErr error)
- func (m *Cache[ENT, ID]) DropCachedValues(ctx context.Context) (rErr error)
- func (m *Cache[ENT, ID]) FindAll(ctx context.Context) (iter.Seq2[ENT, error], error)
- func (m *Cache[ENT, ID]) FindByID(ctx context.Context, id ID) (ENT, bool, error)
- func (m *Cache[ENT, ID]) HitIDFindAll() HitID
- func (m *Cache[ENT, ID]) HitIDFindByID(id ID) HitID
- func (m *Cache[ENT, ID]) Idle() bool
- func (m *Cache[ENT, ID]) InvalidateByID(ctx context.Context, id ID) (rErr error)
- func (m *Cache[ENT, ID]) InvalidateCachedQuery(ctx context.Context, hitID HitID) (rErr error)
- func (m *Cache[ENT, ID]) Refresh(ctx context.Context) (rErr error)
- func (m *Cache[ENT, ID]) RefreshByID(ctx context.Context, id ID) (rErr error)
- func (m *Cache[ENT, ID]) RefreshQueryMany(ctx context.Context, hitID HitID, query QueryManyFunc[ENT]) (rErr error)
- func (m *Cache[ENT, ID]) RefreshQueryOne(ctx context.Context, hitID HitID, query QueryOneFunc[ENT]) (rErr error)
- func (m *Cache[ENT, ID]) Save(ctx context.Context, ptr *ENT) error
- func (m *Cache[ENT, ID]) Update(ctx context.Context, ptr *ENT) error
- type EntityRepository
- type Hit
- type HitID
- type HitRepository
- type Interface
- type Invalidator
- type Locks
- type Query
- type QueryARGS
- type QueryManyFunc
- type QueryOneFunc
- type RefreshCache
- type Repository
- type Source
Examples ¶
Constants ¶
const ErrNotImplementedBySource errorkit.Error = "the method is not implemented by the cache source"
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Cache ¶
type Cache[ENT any, ID comparable] struct { // Source is the location of the original data Source Source[ENT, ID] // Repository is the resource that keeps the cached data. Repository Repository[ENT, ID] // IDA [optional] is the ENT's ID accessor. // // default: extid Lookup/Set IDA extid.Accessor[ENT, ID] // Invalidators [optional] is a list of invalidation rule which is being used whenever an entity is being invalidated. // It is ideal to invalidate a query by reconstucting the cache.HitID using the contents of the ENT OR ID. Invalidators []Invalidator[ENT, ID] // RefreshBehind [optional] enables background refreshing of cache. // When set to true, after the cache serves stale data, it triggers an // asynchronous update from the data source to refresh the cache in the background. // This ensures eventual consistency without blocking read operations. // // If you want to ensure that Refresh-Behind queries don't overlap between parallel cache instances, // then make sure that Scheduler uses a distributed locking. // // default: false RefreshBehind bool // Locks is used to sync background task scheduling. // RefreshBehind depends on Locks. // // default: process level locking Locks Locks // contains filtered or unexported fields }
Cache supplies Read/Write-Through caching to CRUD resources.
func New ¶
func New[ENT any, ID comparable]( source Source[ENT, ID], cacheRepo Repository[ENT, ID], ) *Cache[ENT, ID]
func (*Cache[ENT, ID]) CachedQueryMany ¶
func (*Cache[ENT, ID]) CachedQueryOne ¶
func (*Cache[ENT, ID]) DeleteByID ¶
func (*Cache[ENT, ID]) DropCachedValues ¶
func (*Cache[ENT, ID]) HitIDFindAll ¶ added in v0.252.0
func (*Cache[ENT, ID]) HitIDFindByID ¶ added in v0.252.0
func (*Cache[ENT, ID]) InvalidateByID ¶
InvalidateByID will as the name suggest, invalidate an entity from the cache.
If you have CachedQueryMany and CachedQueryOne usage, then you must use InvalidateCachedQuery instead of this. This is requires because if absence of an entity is cached in the HitRepository, then it is impossible to determine how to invalidate those queries using an ENT ID.
func (*Cache[ENT, ID]) InvalidateCachedQuery ¶
func (*Cache[ENT, ID]) RefreshByID ¶ added in v0.252.0
func (*Cache[ENT, ID]) RefreshQueryMany ¶ added in v0.252.0
func (*Cache[ENT, ID]) RefreshQueryOne ¶ added in v0.252.0
type EntityRepository ¶
type HitRepository ¶
type HitRepository[EntID any] interface { crud.Saver[Hit[EntID]] crud.Finder[Hit[EntID], HitID] crud.Deleter[HitID] }
HitRepository is the query hit result repository.
type Interface ¶
type Interface[ENT, ID any] interface { CachedQueryOne(ctx context.Context, hid HitID, query QueryOneFunc[ENT]) (_ent ENT, _found bool, _err error) CachedQueryMany(ctx context.Context, hid HitID, query QueryManyFunc[ENT]) (iter.Seq2[ENT, error], error) InvalidateCachedQuery(ctx context.Context, hid HitID) error InvalidateByID(ctx context.Context, id ID) (rErr error) DropCachedValues(ctx context.Context) error }
type Invalidator ¶ added in v0.247.0
type Invalidator[ENT, ID any] struct { // CheckEntity checks an entity which is being invalidated, and using its properties, // you can construct the entity values CheckEntity func(ent ENT) []HitID // CheckHit meant to check a Hit to decide if it needs to be invalidated. // If CheckHit returns with true, then the hit will be invalidated. CheckHit func(hit Hit[ID]) bool }
Invalidator is a list of invalidation rule which is being used whenever an entity is being invalidated. It is ideal to invalidate a query by reconstucting the cache.HitID using the contents of the ENT OR ID.
type Locks ¶ added in v0.248.1
type Locks interface { guard.NonBlockingLockerFactory[HitID] }
type Query ¶ added in v0.244.0
type Query struct { // Name is the name of the repository's query operation. // A method name or any unique deterministic name is sufficient. Name constant.String // ARGS contain parameters to the query that can affect the query result. // Supplying the ARGS ensures that a query call with different arguments cached individually. // Request lifetime related values are not expected to be part of ARGS. // ARGS should contain values that are serializable. ARGS QueryARGS // Version can help supporting multiple version of the same cached operation, // so if the application rolls out with a new version, that has different behaviour or fifferend signature // these values can be distringuesed Version int }
Query is a helper that allows you to create a cache.HitID
type QueryManyFunc ¶
type QueryOneFunc ¶
type RefreshCache ¶ added in v0.292.0
type RefreshCache[T any] struct { // Refresh [REQUIRED] is a mandatory function that fetches a new value when the current cache entry is expired or missing. // // This must be provided; otherwise, calls to Load will panic. Refresh func(ctx context.Context) (T, error) // IsExpired [OPTIONAL] is custom expiration checker. // If set, it determines whether the current cached value has expired. // // The function takes a context and the cached value T as inputs, returning true if expired or false otherwise. // Errors returned by this function are propagated to callers of Load(). IsExpired func(ctx context.Context, v T) (bool, error) // TimeToLive [OPTIONAL] is a duration specifying how long the cached value remains valid before automatic refresh occurs. // // A zero or negative value disables TTL-based expiration. TimeToLive time.Duration // contains filtered or unexported fields }
AutoRefreshCache is a generic cache that automatically refreshes its stored value when it becomes expired.
It supports optional custom expiration logic via IsExpired and TTL-based expiration. Only the Refresh function is mandatory;
if either IsExpired or TimeToLive are provided, they define additional conditions for when to trigger a refresh. If both IsExpired and TimeToLive are provided, the cache will expire the value when either condition is met.
Example (WithCombinedTTLStrategy) ¶
package main import ( "context" "time" "go.llib.dev/frameless/pkg/cache" "go.llib.dev/testcase/clock" ) func main() { type Token struct { ExpireAt time.Time } type TokenIssuer interface { CreateToken(context.Context) (Token, error) } var tokenIssuer TokenIssuer m := cache.RefreshCache[Token]{ Refresh: func(ctx context.Context) (Token, error) { return tokenIssuer.CreateToken(ctx) }, IsExpired: func(ctx context.Context, v Token) (bool, error) { return clock.Now().After(v.ExpireAt), nil }, TimeToLive: time.Hour, } tkn, err := m.Load(context.Background()) _, _ = tkn, err }
Output:
Example (WithTimeToLive) ¶
package main import ( "context" "time" "go.llib.dev/frameless/pkg/cache" ) func main() { type Token struct { ExpireAt time.Time } type TokenIssuer interface { CreateToken(context.Context) (Token, error) } var tokenIssuer TokenIssuer m := cache.RefreshCache[Token]{ Refresh: func(ctx context.Context) (Token, error) { return tokenIssuer.CreateToken(ctx) }, TimeToLive: time.Hour, // values expire after an hour } tkn, err := m.Load(context.Background()) _, _ = tkn, err }
Output:
Example (WithValueSpecificExpirationLogic) ¶
package main import ( "context" "time" "go.llib.dev/frameless/pkg/cache" "go.llib.dev/testcase/clock" ) func main() { type Token struct { ExpireAt time.Time } type TokenIssuer interface { CreateToken(context.Context) (Token, error) } var tokenIssuer TokenIssuer m := cache.RefreshCache[Token]{ Refresh: func(ctx context.Context) (Token, error) { return tokenIssuer.CreateToken(ctx) }, // Values expire based on the custom logic of IsExpired IsExpired: func(ctx context.Context, v Token) (bool, error) { return clock.Now().After(v.ExpireAt), nil }, } tkn, err := m.Load(context.Background()) _, _ = tkn, err }
Output:
type Repository ¶
type Repository[ENT, ID any] interface { comproto.OnePhaseCommitProtocol Entities() EntityRepository[ENT, ID] Hits() HitRepository[ID] }
type Source ¶
type Source[ENT, ID any] interface { crud.ByIDFinder[ENT, ID] }
Source is the minimum expected interface that is expected from a Source resources that needs caching. On top of this, cache.Cache also supports Updater, CreatorPublisher, UpdaterPublisher and DeleterPublisher.