Practice Go: Cache Client
Jan 2, 2017
1 minute read

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
}

Back to posts