func (c *LoadingCache) DeleteExpired() {
	c.Lock()
	defer c.Unlock()
	c.purge(0)
}
DeleteExpired clears cache of expired items
package cache
import (
	"sort"
	"sync"
	"time"
	"github.com/pkg/errors"
)
type LoadingCache struct {
	purgeEvery time.Duration
	ttl        time.Duration
	maxKeys    int64
	done       chan struct{}
	onEvicted  func(key string, value interface{})
	sync.Mutex
	data map[string]*cacheItem
}
const noEvictionTTL = time.Hour * 24 * 365 * 10
func NewLoadingCache(options ...Option) (*LoadingCache, error) {
	res := LoadingCache{
		data:       map[string]*cacheItem{},
		ttl:        noEvictionTTL,
		purgeEvery: 0,
		maxKeys:    0,
		done:       make(chan struct{}),
	}
	for _, opt := range options {
		if err := opt(&res); err != nil {
			return nil, errors.Wrap(err, "failed to set cache option")
		}
	}
	if res.maxKeys > 0 || res.purgeEvery > 0 {
		if res.purgeEvery == 0 {
			res.purgeEvery = time.Minute * 5  
		}
		go func(done <-chan struct{}) {
			ticker := time.NewTicker(res.purgeEvery)
			for {
				select {
				case <-done:
					return
				case <-ticker.C:
					res.Lock()
					res.purge(res.maxKeys)
					res.Unlock()
				}
			}
		}(res.done)
	}
	return &res, nil
}
func (c *LoadingCache) Set(key string, value interface{}) {
	c.Lock()
	defer c.Unlock()
	now := time.Now()
	if _, ok := c.data[key]; !ok {
		c.data[key] = &cacheItem{}
	}
	c.data[key].data = value
	c.data[key].expiresAt = now.Add(c.ttl)
	if c.maxKeys > 0 && int64(len(c.data)) >= c.maxKeys*2 {
		c.purge(c.maxKeys)
	}
}
func (c *LoadingCache) Get(key string) (interface{}, bool) {
	c.Lock()
	defer c.Unlock()
	value, ok := c.getValue(key)
	if !ok {
		return nil, false
	}
	return value, ok
}
func (c *LoadingCache) Peek(key string) (interface{}, bool) {
	c.Lock()
	defer c.Unlock()
	value, ok := c.getValue(key)
	if !ok {
		return nil, false
	}
	return value, ok
}
func (c *LoadingCache) Invalidate(key string) {
	c.Lock()
	if value, ok := c.data[key]; ok {
		delete(c.data, key)
		if c.onEvicted != nil {
			c.onEvicted(key, value.data)
		}
	}
	c.Unlock()
}
func (c *LoadingCache) InvalidateFn(fn func(key string) bool) {
	c.Lock()
	for key, value := range c.data {
		if fn(key) {
			delete(c.data, key)
			if c.onEvicted != nil {
				c.onEvicted(key, value.data)
			}
		}
	}
	c.Unlock()
}
func (c *LoadingCache) Keys() []string {
	c.Lock()
	defer c.Unlock()
	keys := make([]string, 0, len(c.data))
	for k := range c.data {
		keys = append(keys, k)
	}
	return keys
}
func (c *LoadingCache) getValue(key string) (interface{}, bool) {
	value, ok := c.data[key]
	if !ok {
		return nil, false
	}
	if time.Now().After(c.data[key].expiresAt) {
		return nil, false
	}
	return value.data, ok
}
func (c *LoadingCache) Purge() {
	c.Lock()
	defer c.Unlock()
	for k, v := range c.data {
		delete(c.data, k)
		if c.onEvicted != nil {
			c.onEvicted(k, v.data)
		}
	}
}