Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Loadable and Expiration #101

Closed
amaioli opened this issue Jun 19, 2021 · 6 comments
Closed

Loadable and Expiration #101

amaioli opened this issue Jun 19, 2021 · 6 comments

Comments

@amaioli
Copy link

amaioli commented Jun 19, 2021

In the LoadFunction can i manage the key expiration somewhere?

@sgtsquiggs
Copy link
Contributor

sgtsquiggs commented Oct 6, 2022

I also need to be able to set both the TTL and tag for specific loadable Gets

@sgtsquiggs
Copy link
Contributor

Easy enough to make my own copy:

package cache

import (
	"context"
	"sync"

	"github.com/eko/gocache/v3/cache"
	"github.com/eko/gocache/v3/store"
)

const (
	// LoadableType represents the loadable cache type as a string value
	LoadableType = "loadable"
)

type loadableKeyValue[T any] struct {
	key     any
	value   T
	options []store.Option
}

type LoadFunction[T any] func(ctx context.Context, key any) (T, []store.Option, error)

// LoadableCache represents a cache that uses a function to load data
type LoadableCache[T any] struct {
	loadFunc   LoadFunction[T]
	cache      cache.CacheInterface[T]
	setChannel chan *loadableKeyValue[T]
	setterWg   *sync.WaitGroup
}

// NewLoadable instanciates a new cache that uses a function to load data
func NewLoadable[T any](loadFunc LoadFunction[T], cache cache.CacheInterface[T]) *LoadableCache[T] {
	loadable := &LoadableCache[T]{
		loadFunc:   loadFunc,
		cache:      cache,
		setChannel: make(chan *loadableKeyValue[T], 10000),
		setterWg:   &sync.WaitGroup{},
	}

	loadable.setterWg.Add(1)
	go loadable.setter()

	return loadable
}

func (c *LoadableCache[T]) setter() {
	defer c.setterWg.Done()

	for item := range c.setChannel {
		c.Set(context.Background(), item.key, item.value, item.options...)
	}
}

// Get returns the object stored in cache if it exists
func (c *LoadableCache[T]) Get(ctx context.Context, key any) (T, error) {
	var err error

	object, err := c.cache.Get(ctx, key)
	if err == nil {
		return object, err
	}

	// Unable to find in cache, try to load it from load function
	object, options, err := c.loadFunc(ctx, key)
	if err != nil {
		return object, err
	}

	// Then, put it back in cache
	c.setChannel <- &loadableKeyValue[T]{key, object, options}

	return object, err
}

// Set sets a value in available caches
func (c *LoadableCache[T]) Set(ctx context.Context, key any, object T, options ...store.Option) error {
	return c.cache.Set(ctx, key, object, options...)
}

// Delete removes a value from cache
func (c *LoadableCache[T]) Delete(ctx context.Context, key any) error {
	return c.cache.Delete(ctx, key)
}

// Invalidate invalidates cache item from given options
func (c *LoadableCache[T]) Invalidate(ctx context.Context, options ...store.InvalidateOption) error {
	return c.cache.Invalidate(ctx, options...)
}

// Clear resets all cache data
func (c *LoadableCache[T]) Clear(ctx context.Context) error {
	return c.cache.Clear(ctx)
}

// GetType returns the cache type
func (c *LoadableCache[T]) GetType() string {
	return LoadableType
}

func (c *LoadableCache[T]) Close() error {
	close(c.setChannel)
	c.setterWg.Wait()

	return nil
}

@sonu27
Copy link

sonu27 commented Apr 17, 2024

Would be great if the load function supported an optional expiration

@onesaltedseafish
Copy link

it's a good idea to add [] cache.Option in loadFunc, it will be better to have this

@jennryaz
Copy link

@eko are there plans to merge @sgtsquiggs solution from #101 (comment)? It seems to resolve the issue of loadable not supporting expiration? i tested it and seems to work just fine. thank you so much

@eko eko closed this as completed in a997e57 Jan 8, 2025
eko added a commit that referenced this issue Jan 8, 2025
Loadable cache: make options to be re-used in setter (fixes #101)
@eko
Copy link
Owner

eko commented Jan 8, 2025

Hi,

Thank you, this is done, options are now used in setters so TTLs should be respected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants