Awesome
TTLCache - an in-memory cache with item expiration and generics
Features
- Simple API
- Type parameters
- Item expiration and automatic deletion
- Automatic expiration time extension on each
Get
call Loader
interface that may be used to load/lazily initialize missing cache items- Event handlers (insertion and eviction)
- Metrics
Installation
go get github.com/jellydator/ttlcache/v3
Usage
The main type of ttlcache
is Cache
. It represents a single
in-memory data store.
To create a new instance of ttlcache.Cache
, the ttlcache.New()
function
should be called:
func main() {
cache := ttlcache.New[string, string]()
}
Note that by default, a new cache instance does not let any of its
items to expire or be automatically deleted. However, this feature
can be activated by passing a few additional options into the
ttlcache.New()
function and calling the cache.Start()
method:
func main() {
cache := ttlcache.New[string, string](
ttlcache.WithTTL[string, string](30 * time.Minute),
)
go cache.Start() // starts automatic expired item deletion
}
Even though the cache.Start()
method handles expired item deletion well,
there may be times when the system that uses ttlcache
needs to determine
when to delete the expired items itself. For example, it may need to
delete them only when the resource load is at its lowest (e.g., after
midnight, when the number of users/HTTP requests drops). So, in situations
like these, instead of calling cache.Start()
, the system could
periodically call cache.DeleteExpired()
:
func main() {
cache := ttlcache.New[string, string](
ttlcache.WithTTL[string, string](30 * time.Minute),
)
for {
time.Sleep(4 * time.Hour)
cache.DeleteExpired()
}
}
The data stored in ttlcache.Cache
can be retrieved, checked and updated with
Set
, Get
, Delete
, Has
etc. methods:
func main() {
cache := ttlcache.New[string, string](
ttlcache.WithTTL[string, string](30 * time.Minute),
)
// insert data
cache.Set("first", "value1", ttlcache.DefaultTTL)
cache.Set("second", "value2", ttlcache.NoTTL)
cache.Set("third", "value3", ttlcache.DefaultTTL)
// retrieve data
item := cache.Get("first")
fmt.Println(item.Value(), item.ExpiresAt())
// check key
ok := cache.Has("third")
// delete data
cache.Delete("second")
cache.DeleteExpired()
cache.DeleteAll()
// retrieve data if in cache otherwise insert data
item, retrieved := cache.GetOrSet("fourth", "value4", WithTTL[string, string](ttlcache.DefaultTTL))
// retrieve and delete data
item, present := cache.GetAndDelete("fourth")
}
To subscribe to insertion and eviction events, cache.OnInsertion()
and
cache.OnEviction()
methods should be used:
func main() {
cache := ttlcache.New[string, string](
ttlcache.WithTTL[string, string](30 * time.Minute),
ttlcache.WithCapacity[string, string](300),
)
cache.OnInsertion(func(ctx context.Context, item *ttlcache.Item[string, string]) {
fmt.Println(item.Value(), item.ExpiresAt())
})
cache.OnEviction(func(ctx context.Context, reason ttlcache.EvictionReason, item *ttlcache.Item[string, string]) {
if reason == ttlcache.EvictionReasonCapacityReached {
fmt.Println(item.Key(), item.Value())
}
})
cache.Set("first", "value1", ttlcache.DefaultTTL)
cache.DeleteAll()
}
To load data when the cache does not have it, a custom or
existing implementation of ttlcache.Loader
can be used:
func main() {
loader := ttlcache.LoaderFunc[string, string](
func(c *ttlcache.Cache[string, string], key string) *ttlcache.Item[string, string] {
// load from file/make an HTTP request
item := c.Set("key from file", "value from file")
return item
},
)
cache := ttlcache.New[string, string](
ttlcache.WithLoader[string, string](loader),
)
item := cache.Get("key from file")
}