blob: 7a1d2a37b402df7f1b2e121f2267fb82cfe3a42b (
plain) (
blame)
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
|
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package document
import (
"math"
"sync/atomic"
"time"
)
type CircuitState int
const (
// CircuitClosed represents a closed circuit. Documents are processed successfully
CircuitClosed CircuitState = iota
// CircuitHalfOpen represents a half-open circuit. Some errors have happend, but processing may still recover
CircuitHalfOpen
// CircuitOpen represents a open circuit. Something is broken. We should no longer process documents
CircuitOpen
)
type CircuitBreaker interface {
Success()
Failure()
State() CircuitState
}
type timeCircuitBreaker struct {
graceDuration time.Duration
doomDuration time.Duration
failingSinceMillis atomic.Int64
halfOpen atomic.Bool
open atomic.Bool
now func() time.Time
}
func (b *timeCircuitBreaker) Success() {
b.failingSinceMillis.Store(math.MaxInt64)
if !b.open.Load() {
b.halfOpen.CompareAndSwap(true, false)
}
}
func (b *timeCircuitBreaker) Failure() {
b.failingSinceMillis.CompareAndSwap(math.MaxInt64, b.now().UnixMilli())
}
func (b *timeCircuitBreaker) State() CircuitState {
failingDuration := b.now().Sub(time.UnixMilli(b.failingSinceMillis.Load()))
if failingDuration > b.graceDuration {
b.halfOpen.CompareAndSwap(false, true)
}
if b.doomDuration > 0 && failingDuration > b.doomDuration {
b.open.CompareAndSwap(false, true)
}
if b.open.Load() {
return CircuitOpen
} else if b.halfOpen.Load() {
return CircuitHalfOpen
}
return CircuitClosed
}
func NewCircuitBreaker(graceDuration, doomDuration time.Duration) *timeCircuitBreaker {
b := &timeCircuitBreaker{
graceDuration: graceDuration,
doomDuration: doomDuration,
now: time.Now,
}
b.failingSinceMillis.Store(math.MaxInt64)
b.open.Store(false)
b.halfOpen.Store(false)
return b
}
|