forked from trivago/gollum
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fuse.go
54 lines (47 loc) · 1.43 KB
/
fuse.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
package shared
import (
"sync"
"sync/atomic"
)
// Fuse is a local circuit breaker implementation that is ment to be used to
// manage the state of a given resource between different threads of execution
// (consumer/producer). If the resource is not available the fuse is "burned".
// Components may now wait on that fuse and are woken as soon as the resource
// becomes available again (the fuse is "activated" again).
type Fuse struct {
signal *sync.Cond
burned *int32
}
// NewFuse creates a new Fuse and returns it.
// A new fuse is always active.
func NewFuse() *Fuse {
return &Fuse{
signal: sync.NewCond(new(sync.Mutex)),
burned: new(int32),
}
}
// IsBurned returns true if the fuse in the "inactive" state
func (fuse Fuse) IsBurned() bool {
return atomic.LoadInt32(fuse.burned) == 1
}
// Burn sets the fuse back to the "inactive" state.
// An already burned fuse cannot be burned again (call is ignored).
func (fuse *Fuse) Burn() {
atomic.StoreInt32(fuse.burned, 1)
}
// Activate sets the fuse back to the "running" state.
// An already active fuse cannot be activated again (call is ignored).
func (fuse *Fuse) Activate() {
if atomic.CompareAndSwapInt32(fuse.burned, 1, 0) {
fuse.signal.Broadcast()
}
}
// Wait blocks until the fuse enters active state.
// Multiple go routines may wait on the same fuse.
func (fuse Fuse) Wait() {
fuse.signal.L.Lock()
defer fuse.signal.L.Unlock()
if fuse.IsBurned() {
fuse.signal.Wait()
}
}