mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
fn: introducing WaitGroup suitable for shutdown/session mgmt (#936)
* fn: introducing WaitGroup suitable for shutdown/session mgmt
This commit is contained in:
104
api/common/wait_utils.go
Normal file
104
api/common/wait_utils.go
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
WaitGroup is used to manage and wait for a collection of
|
||||||
|
sessions. It is similar to sync.WaitGroup, but
|
||||||
|
AddSession/RmSession/WaitClose session is not only thread
|
||||||
|
safe but can be executed in any order unlike sync.WaitGroup.
|
||||||
|
|
||||||
|
Once a shutdown is initiated via CloseGroup(), add/rm
|
||||||
|
operations will still function correctly, where
|
||||||
|
AddSession would return false error.
|
||||||
|
In this state, CloseGroup() blocks until sessions get drained
|
||||||
|
via RmSession() calls.
|
||||||
|
|
||||||
|
It is an error to call RmSession without a corresponding
|
||||||
|
successful AddSession.
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
|
||||||
|
group := NewWaitGroup()
|
||||||
|
|
||||||
|
for item := range(items) {
|
||||||
|
go func(item string) {
|
||||||
|
if !group.AddSession() {
|
||||||
|
// group may be closing or full
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer group.RmSession()
|
||||||
|
|
||||||
|
// do stuff
|
||||||
|
}(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
// close the group and wait for active item.
|
||||||
|
group.CloseGroup()
|
||||||
|
*/
|
||||||
|
|
||||||
|
type WaitGroup struct {
|
||||||
|
cond *sync.Cond
|
||||||
|
isClosed bool
|
||||||
|
sessions uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWaitGroup() *WaitGroup {
|
||||||
|
return &WaitGroup{
|
||||||
|
cond: sync.NewCond(new(sync.Mutex)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *WaitGroup) AddSession() bool {
|
||||||
|
r.cond.L.Lock()
|
||||||
|
defer r.cond.L.Unlock()
|
||||||
|
|
||||||
|
if r.isClosed {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if r.sessions == math.MaxUint64 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
r.sessions++
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *WaitGroup) RmSession() {
|
||||||
|
r.cond.L.Lock()
|
||||||
|
|
||||||
|
if r.sessions == 0 {
|
||||||
|
panic("WaitGroup misuse: no sessions to remove")
|
||||||
|
}
|
||||||
|
|
||||||
|
r.sessions--
|
||||||
|
r.cond.Broadcast()
|
||||||
|
|
||||||
|
r.cond.L.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *WaitGroup) CloseGroup() {
|
||||||
|
r.cond.L.Lock()
|
||||||
|
|
||||||
|
r.isClosed = true
|
||||||
|
for r.sessions > 0 {
|
||||||
|
r.cond.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
r.cond.L.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *WaitGroup) CloseGroupNB() chan struct{} {
|
||||||
|
|
||||||
|
closer := make(chan struct{})
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer close(closer)
|
||||||
|
r.CloseGroup()
|
||||||
|
}()
|
||||||
|
|
||||||
|
return closer
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user