github.com/sandwich-go/boost@v1.3.29/singleflight/single.go (about) 1 // Package singleflight provides a duplicate function call suppression 2 // mechanism. 3 package singleflight 4 5 import ( 6 "github.com/sandwich-go/boost/xerror" 7 "github.com/sandwich-go/boost/xpanic" 8 "sync" 9 ) 10 11 // call is an in-flight or completed Do call 12 type call struct { 13 wg sync.WaitGroup 14 val interface{} 15 err error 16 } 17 18 // New create a group 19 func New() *Group { return &Group{} } 20 21 // Group represents a class of work and forms a namespace in which 22 // units of work can be executed with duplicate suppression. 23 type Group struct { 24 mu sync.Mutex // protects m 25 m map[string]*call // lazily initialized 26 } 27 28 // Do executes and returns the results of the given function, making 29 // sure that only one execution is in-flight for a given key at a 30 // time. If a duplicate comes in, the duplicate caller waits for the 31 // original to complete and receives the same results. 32 func (g *Group) Do(key string, fn func() (interface{}, error)) (interface{}, error) { 33 g.mu.Lock() 34 if g.m == nil { 35 g.m = make(map[string]*call) 36 } 37 if c, ok := g.m[key]; ok { 38 g.mu.Unlock() 39 c.wg.Wait() 40 return c.val, c.err 41 } 42 c := new(call) 43 c.wg.Add(1) 44 g.m[key] = c 45 g.mu.Unlock() 46 47 xpanic.Do(func() { 48 c.val, c.err = fn() 49 }, func(p *xpanic.Panic) { 50 c.err = xerror.NewText("panic with: %v", p) 51 }) 52 53 c.wg.Done() 54 55 g.mu.Lock() 56 delete(g.m, key) 57 g.mu.Unlock() 58 59 return c.val, c.err 60 }