Peng Yan
Practice Go: Cache Client
Task: cache client with go
Since go is design for easy compose concurrency-safe code. There are some ways to adopt it.
To make client concurrency-safe, need to use lock without harming too much efficiency.
By using Context, we allow client call able to timeout safe without leaking goroutine.
func (c *Client) Call(ctx context.Context, key string) (value interface{}, err error) {
c.Lock()
e := c.cache[key]
if e == nil {
e = &CStruct{key, make(chan struct{}), nil}
c.cache[key] = e
c.Unlock()
e.result = c.flist(key)
close(e.ready)
} else {
c.Unlock()
}
select {
case <-ctx.Done():
return nil, ctx.Err()
case <-e.ready:
return e.result, nil
}
}
type CStruct struct {
key string
ready chan struct{}
result interface{}
}
type Client struct {
cache map[string]*CStruct
sync.Mutex
flist func(key string) interface{}
}
type Config struct {
Function func(key string) interface{}
}
func New(config ...Config) (*Client, error) {
// option config
c := &Client{cache: make(map[string]*CStruct)}
c.flist = config[0].Function
return c, nil
}