-
Notifications
You must be signed in to change notification settings - Fork 0
/
stateful_func.go
82 lines (69 loc) · 1.63 KB
/
stateful_func.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
package routines
import (
"errors"
"sync"
)
var ErrRunning = errors.New("StatefulFunc: function is running")
// StatefulFunc is a function that possible to get current running state
type StatefulFunc interface {
IsRunning() bool
// try to run the function now, return ErrRunning immediately if it is running
TryRun() (err error)
// run this function, blocks until ran
Run() (err error)
// blocks until it's free to run, and hold the lock to prevent others running
// calling Run() without release the lock cause deadlock! use with care.
//
// It's safe to call release multiple times, only first time is executed.
Lock() (release func())
}
type statefulFunc struct {
token chan *struct{}
f func() error
}
func (f *statefulFunc) IsRunning() (yes bool) {
select {
case x := <-f.token:
f.token <- x
return false
default:
return true
}
}
func (f *statefulFunc) TryRun() (err error) {
select {
case x := <-f.token:
err = f.f()
f.token <- x
default:
err = ErrRunning
}
return
}
func (f *statefulFunc) Run() (err error) {
x := <-f.token
err = f.f()
f.token <- x
return
}
func (f *statefulFunc) Lock() (release func()) {
x := <-f.token
once := &sync.Once{}
return func() {
once.Do(func() {
f.token <- x
})
}
}
// NewStatefulFunc creates a new StatefulFunc
func NewStatefulFunc(f func() error) (ret StatefulFunc) {
x := &statefulFunc{
token: make(chan *struct{}, 1),
f: f,
}
x.token <- nil
return x
}