Skip to content

Commit 720f9b5

Browse files
committed
refactor: add example
1 parent 5efb229 commit 720f9b5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+2299
-19
lines changed

LICENSE

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
BSD 3-Clause License
2+
3+
Copyright (c) 2019, (0x794E6).toString(36)
4+
All rights reserved.
5+
6+
Redistribution and use in source and binary forms, with or without
7+
modification, are permitted provided that the following conditions are met:
8+
9+
* Redistributions of source code must retain the above copyright notice, this
10+
list of conditions and the following disclaimer.
11+
12+
* Redistributions in binary form must reproduce the above copyright notice,
13+
this list of conditions and the following disclaimer in the documentation
14+
and/or other materials provided with the distribution.
15+
16+
* Neither the name of the copyright holder nor the names of its
17+
contributors may be used to endorse or promote products derived from
18+
this software without specific prior written permission.
19+
20+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Makefile

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.PHONY: all help test doc
2+
3+
all: help
4+
5+
help: ## Show this help
6+
@scripts/help.sh
7+
8+
test: ## Test potential bugs and race conditions
9+
@scripts/test.sh
10+
11+
doc: ## Generate docs
12+
@scripts/doc.sh

README.md

+61-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,67 @@
11
# Adaptive Accrual Failure Detector
22

3-
Failure detection for processes, connections and distributed systems.
3+
[![Documentation](https://godoc.org/github.com/andy2046/failured?status.svg)](http://godoc.org/github.com/andy2046/failured)
4+
[![GitHub issues](https://img.shields.io/github/issues/andy2046/failured.svg)](https://github.com/andy2046/failured/issues)
5+
[![license](https://img.shields.io/github/license/andy2046/failured.svg)](https://github.com/andy2046/failured/LICENSE)
6+
[![Release](https://img.shields.io/github/release/andy2046/failured.svg?label=Release)](https://github.com/andy2046/failured/releases)
7+
8+
----
9+
10+
## There is NO perfect failure detector.
11+
12+
## It's a trade-off between completeness and accuracy.
13+
14+
## Failure detection is not a binary value.
15+
416
This is an implementation of a failure detector that uses
517
an adaptive accrual algorithm. The theory of this failure detector is taken from the paper
618
[A New Adaptive Accrual Failure Detector for Dependable Distributed Systems](https://dl.acm.org/citation.cfm?id=1244129).
719

8-
This failure detector is useful for detecting things such as network failures between nodes.
20+
This failure detector is useful for detecting connections failures between nodes in distributed systems.
21+
22+
for documentation, view the [API reference](./doc.md)
23+
24+
25+
## Install
26+
27+
```
28+
go get github.com/andy2046/failured
29+
```
30+
31+
## Usage
32+
33+
```go
34+
package main
35+
36+
import (
37+
"time"
38+
39+
"github.com/andy2046/failured"
40+
)
41+
42+
func main() {
43+
fd := failured.New()
44+
closer := make(chan struct{})
45+
46+
// call RegisterHeartbeat every second
47+
go func() {
48+
for {
49+
select {
50+
case <-closer:
51+
return
52+
default:
53+
}
54+
55+
time.Sleep(time.Second)
56+
fd.RegisterHeartbeat()
57+
}
58+
}()
59+
60+
time.Sleep(3 * time.Second)
61+
close(closer)
62+
63+
// check FailureProbability
64+
p := fd.FailureProbability()
65+
println("failure probability is", p)
66+
}
67+
```

doc.md

+152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
2+
3+
# failured
4+
`import "github.com/andy2046/failured"`
5+
6+
* [Overview](#pkg-overview)
7+
* [Index](#pkg-index)
8+
* [Subdirectories](#pkg-subdirectories)
9+
10+
## <a name="pkg-overview">Overview</a>
11+
Package failured implements the Adaptive Accrual Failure Detector
12+
13+
This package implements [A New Adaptive Accrual Failure Detector for Dependable Distributed Systems](<a href="https://dl.acm.org/citation.cfm?id=1244129">https://dl.acm.org/citation.cfm?id=1244129</a>)
14+
15+
To use the failure detector, you need a heartbeat loop that will
16+
call RegisterHeartbeat() at regular intervals. At any point, you can call FailureProbability() which will
17+
report the suspicion level since the last time RegisterHeartbeat() was called.
18+
19+
20+
21+
22+
## <a name="pkg-index">Index</a>
23+
* [Variables](#pkg-variables)
24+
* [type Config](#Config)
25+
* [type Detector](#Detector)
26+
* [func New(options ...Option) *Detector](#New)
27+
* [func (d *Detector) CheckFailure(now ...int64) bool](#Detector.CheckFailure)
28+
* [func (d *Detector) FailureProbability(now ...int64) float64](#Detector.FailureProbability)
29+
* [func (d *Detector) RegisterHeartbeat(now ...int64)](#Detector.RegisterHeartbeat)
30+
* [type Option](#Option)
31+
32+
33+
#### <a name="pkg-files">Package files</a>
34+
[failured.go](/src/github.com/andy2046/failured/failured.go)
35+
36+
37+
38+
## <a name="pkg-variables">Variables</a>
39+
``` go
40+
var (
41+
// DefaultConfig is the default Detector Config.
42+
DefaultConfig = Config{
43+
WindowSize: 1000,
44+
Factor: 0.9,
45+
FailureThreshold: 0.5,
46+
}
47+
)
48+
```
49+
50+
51+
52+
## <a name="Config">type</a> [Config](/src/target/failured.go?s=1129:1275#L46)
53+
``` go
54+
type Config struct {
55+
// max size of inter-arrival time list
56+
WindowSize uint64
57+
// a scaling factor
58+
Factor float64
59+
60+
FailureThreshold float64
61+
}
62+
```
63+
Config used to init Detector.
64+
65+
66+
67+
68+
69+
70+
71+
72+
73+
74+
## <a name="Detector">type</a> [Detector](/src/target/failured.go?s=752:1092#L29)
75+
``` go
76+
type Detector struct {
77+
// contains filtered or unexported fields
78+
}
79+
```
80+
Detector is a failure detector.
81+
82+
83+
84+
85+
86+
87+
88+
### <a name="New">func</a> [New](/src/target/failured.go?s=1558:1595#L69)
89+
``` go
90+
func New(options ...Option) *Detector
91+
```
92+
New returns a new failure detector.
93+
94+
95+
96+
97+
98+
### <a name="Detector.CheckFailure">func</a> (\*Detector) [CheckFailure](/src/target/failured.go?s=3186:3236#L145)
99+
``` go
100+
func (d *Detector) CheckFailure(now ...int64) bool
101+
```
102+
CheckFailure returns true if `FailureProbability` is
103+
equal to or higher than `FailureThreshold`.
104+
`now` is the current time in Microseconds.
105+
106+
107+
108+
109+
### <a name="Detector.FailureProbability">func</a> (\*Detector) [FailureProbability](/src/target/failured.go?s=2554:2613#L112)
110+
``` go
111+
func (d *Detector) FailureProbability(now ...int64) float64
112+
```
113+
FailureProbability calculates the suspicion level at time `now`
114+
that the remote end has failed.
115+
`now` is the current time in Milliseconds,
116+
default to time.Now() in Milliseconds.
117+
118+
119+
120+
121+
### <a name="Detector.RegisterHeartbeat">func</a> (\*Detector) [RegisterHeartbeat](/src/target/failured.go?s=1998:2048#L86)
122+
``` go
123+
func (d *Detector) RegisterHeartbeat(now ...int64)
124+
```
125+
RegisterHeartbeat registers a heartbeat at time `now`.
126+
`now` is the time in Milliseconds at which the heartbeat was received,
127+
default to time.Now() in Milliseconds.
128+
129+
130+
131+
132+
## <a name="Option">type</a> [Option](/src/target/failured.go?s=1324:1352#L56)
133+
``` go
134+
type Option = func(*Config) error
135+
```
136+
Option applies config to Detector Config.
137+
138+
139+
140+
141+
142+
143+
144+
145+
146+
147+
148+
149+
150+
151+
- - -
152+
Generated by [godoc2md](http://godoc.org/github.com/davecheney/godoc2md)

failure_test.go

+25-15
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,23 @@ func TestNoVariation(t *testing.T) {
2323
lastTime := withDiffs(fd, 1, 1, 1, 1)
2424

2525
data := []struct {
26-
expected float64
27-
v int64
26+
expectedVal float64
27+
expectedBool bool
28+
v int64
2829
}{
29-
{0, lastTime},
30-
{0, lastTime + 1},
31-
{1, lastTime + 2},
30+
{0, false, lastTime},
31+
{0, false, lastTime + 1},
32+
{1, true, lastTime + 2},
3233
}
3334

3435
for _, d := range data {
3536
p := fd.FailureProbability(d.v)
36-
if p != d.expected {
37-
t.Fatalf("expected %v got %v", d.expected, p)
37+
if p != d.expectedVal {
38+
t.Fatalf("expected %v got %v", d.expectedVal, p)
39+
}
40+
b := fd.CheckFailure(d.v)
41+
if b != d.expectedBool {
42+
t.Fatalf("expected %v got %v", d.expectedBool, b)
3843
}
3944
}
4045

@@ -45,19 +50,24 @@ func TestVariation(t *testing.T) {
4550
lastTime := withDiffs(fd, 1010, 1023, 1012, 1032, 1016, 1020, 990, 1028)
4651

4752
data := []struct {
48-
expected float64
49-
v int64
53+
expectedVal float64
54+
expectedBool bool
55+
v int64
5056
}{
51-
{0, lastTime + 500},
52-
{0, lastTime + 1000},
53-
{0.125, lastTime + 1100},
54-
{1, lastTime + 2100},
57+
{0, false, lastTime + 500},
58+
{0, false, lastTime + 1000},
59+
{0.125, false, lastTime + 1100},
60+
{1, true, lastTime + 2100},
5561
}
5662

5763
for _, d := range data {
5864
p := fd.FailureProbability(d.v)
59-
if p != d.expected {
60-
t.Fatalf("expected %v got %v", d.expected, p)
65+
if p != d.expectedVal {
66+
t.Fatalf("expected %v got %v", d.expectedVal, p)
67+
}
68+
b := fd.CheckFailure(d.v)
69+
if b != d.expectedBool {
70+
t.Fatalf("expected %v got %v", d.expectedBool, b)
6171
}
6272
}
6373

failured.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ func (d *Detector) RegisterHeartbeat(now ...int64) {
101101
}
102102

103103
d.samples[d.nextIndex&d.mask] = float64(tt - d.freshness)
104-
d.nextIndex += 1
104+
d.nextIndex++
105105
d.freshness = tt
106106
}
107107

@@ -132,7 +132,7 @@ func (d *Detector) FailureProbability(now ...int64) float64 {
132132

133133
for i := uint64(0); i < total; i++ {
134134
if d.samples[i] <= t {
135-
count += 1
135+
count++
136136
}
137137
}
138138

scripts/doc.sh

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env bash
2+
3+
set -euo pipefail
4+
5+
godoc2md github.com/andy2046/failured \
6+
> $GOPATH/src/github.com/andy2046/failured/doc.md

scripts/help.sh

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/usr/bin/env bash
2+
3+
set -euo pipefail
4+
5+
echo 'usage: make [target] ...'
6+
echo
7+
echo 'targets:'
8+
fgrep -h "##" ./Makefile | fgrep -v fgrep | sed -e 's/\\$$//' | sed -e 's/##//'

scripts/test.sh

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/usr/bin/env bash
2+
3+
set -euo pipefail
4+
5+
go test -count=1 -v -cover -race
6+
go test -bench=. -run=none -benchtime=3s
7+
go fmt
8+
go vet
9+
golint

vendor/golang.org/x/sys/AUTHORS

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/golang.org/x/sys/CONTRIBUTORS

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)