@@ -3,69 +3,109 @@ package atlas
3
3
import (
4
4
"context"
5
5
"strconv"
6
+ "strings"
6
7
"sync"
8
+ "time"
7
9
8
10
"github.com/DNS-OARC/ripeatlas/measurement"
9
11
"github.com/prometheus/common/log"
10
12
11
13
"github.com/DNS-OARC/ripeatlas"
12
14
)
13
15
16
+ const ConnectionRetryInterval = 30 * time .Second
17
+
14
18
type streamingStrategy struct {
15
19
stream * ripeatlas.Stream
16
20
results map [string ]map [int ]* measurement.Result
17
21
workers uint
22
+ timeout time.Duration
18
23
mu sync.RWMutex
19
24
}
20
25
21
26
// NewStreamingStrategy returns an strategy using the RIPE Atlas Streaming API
22
- func NewStreamingStrategy (ctx context.Context , ids []string , workers uint ) ( Strategy , error ) {
27
+ func NewStreamingStrategy (ctx context.Context , ids []string , workers uint , timeout time. Duration ) Strategy {
23
28
s := & streamingStrategy {
24
29
stream : ripeatlas .NewStream (),
25
30
workers : workers ,
31
+ timeout : timeout ,
26
32
results : make (map [string ]map [int ]* measurement.Result ),
27
33
}
28
34
29
- err := s .start (ctx , ids )
30
- if err != nil {
31
- return nil , err
32
- }
33
-
34
- return s , nil
35
+ s .start (ctx , ids )
36
+ return s
35
37
}
36
38
37
- func (s * streamingStrategy ) start (ctx context.Context , ids []string ) error {
39
+ func (s * streamingStrategy ) start (ctx context.Context , ids []string ) {
38
40
for _ , id := range ids {
39
- msm , err := strconv .Atoi (id )
41
+ go s .startListening (ctx , id )
42
+ }
43
+ }
44
+
45
+ func (s * streamingStrategy ) startListening (ctx context.Context , id string ) {
46
+ for {
47
+ ch , err := s .subscribe (id )
40
48
if err != nil {
41
- return err
49
+ log .Error (err )
50
+ } else {
51
+ log .Infof ("Subscribed to results of measurement #%s" , id )
52
+ s .listenForResults (ctx , ch )
42
53
}
43
54
44
- ch , err := s .stream .MeasurementResults (ripeatlas.Params {
45
- "msm" : msm ,
46
- })
47
- if err != nil {
48
- return err
55
+ select {
56
+ case <- ctx .Done ():
57
+ return
58
+ case <- time .After (ConnectionRetryInterval ):
59
+ delete (s .results , id )
60
+ continue
49
61
}
62
+ }
63
+ }
64
+
65
+ func (s * streamingStrategy ) subscribe (id string ) (<- chan * measurement.Result , error ) {
66
+ msm , err := strconv .Atoi (id )
67
+ if err != nil {
68
+ return nil , err
69
+ }
50
70
51
- go s .listenForResults (ctx , ch )
71
+ ch , err := s .stream .MeasurementResults (ripeatlas.Params {
72
+ "msm" : msm ,
73
+ })
74
+ if err != nil {
75
+ return nil , err
52
76
}
53
77
54
- return nil
78
+ return ch , nil
55
79
}
56
80
57
81
func (s * streamingStrategy ) listenForResults (ctx context.Context , ch <- chan * measurement.Result ) {
58
82
for {
59
83
select {
60
84
case m := <- ch :
61
- go s .warmProbeCache (m )
62
- s .addOrReplace (m )
85
+ if m .ParseError != nil {
86
+ log .Error (m .ParseError )
87
+ }
88
+
89
+ if m .ParseError != nil && strings .HasPrefix (m .ParseError .Error (), "c.On(disconnect)" ) {
90
+ log .Error (m .ParseError )
91
+ return
92
+ }
93
+
94
+ s .processMeasurement (m )
95
+ case <- time .After (s .timeout ):
96
+ log .Errorf ("Timeout reached. Trying to reconnect." )
97
+ return
63
98
case <- ctx .Done ():
64
99
return
65
100
}
66
101
}
67
102
}
68
103
104
+ func (s * streamingStrategy ) processMeasurement (m * measurement.Result ) {
105
+ go s .warmProbeCache (m )
106
+ s .addOrReplace (m )
107
+ }
108
+
69
109
func (s * streamingStrategy ) warmProbeCache (m * measurement.Result ) {
70
110
_ , err := probeForID (m .PrbId ())
71
111
if err != nil {
0 commit comments