Make Send/Write Loop context aware (#837)
Jose Luis Ordiales Coscia authored 4 years ago
Peter Bourgon committed 4 years ago
67 | 67 | |
68 | 68 | ```go |
69 | 69 | import ( |
70 | "context" | |
70 | 71 | "net" |
71 | 72 | "os" |
72 | 73 | "runtime" |
80 | 81 | statsd := statsd.New("foo_svc.", log.NewNopLogger()) |
81 | 82 | report := time.NewTicker(5 * time.Second) |
82 | 83 | defer report.Stop() |
83 | go statsd.SendLoop(report.C, "tcp", "statsd.internal:8125") | |
84 | go statsd.SendLoop(context.Background(), report.C, "tcp", "statsd.internal:8125") | |
84 | 85 | goroutines := statsd.NewGauge("goroutine_count") |
85 | 86 | go exportGoroutines(goroutines) |
86 | 87 | // ... |
0 | 0 | package cloudwatch |
1 | 1 | |
2 | 2 | import ( |
3 | "context" | |
3 | 4 | "fmt" |
4 | 5 | "os" |
6 | "strconv" | |
5 | 7 | "sync" |
6 | 8 | "time" |
7 | 9 | |
13 | 15 | "github.com/go-kit/kit/metrics" |
14 | 16 | "github.com/go-kit/kit/metrics/generic" |
15 | 17 | "github.com/go-kit/kit/metrics/internal/lv" |
16 | "strconv" | |
17 | 18 | ) |
18 | 19 | |
19 | 20 | const ( |
135 | 136 | } |
136 | 137 | |
137 | 138 | // WriteLoop is a helper method that invokes Send every time the passed |
138 | // channel fires. This method blocks until the channel is closed, so clients | |
139 | // channel fires. This method blocks until ctx is canceled, so clients | |
139 | 140 | // probably want to run it in its own goroutine. For typical usage, create a |
140 | 141 | // time.Ticker and pass its C channel to this method. |
141 | func (cw *CloudWatch) WriteLoop(c <-chan time.Time) { | |
142 | for range c { | |
143 | if err := cw.Send(); err != nil { | |
144 | cw.logger.Log("during", "Send", "err", err) | |
142 | func (cw *CloudWatch) WriteLoop(ctx context.Context, c <-chan time.Time) { | |
143 | for { | |
144 | select { | |
145 | case <-c: | |
146 | if err := cw.Send(); err != nil { | |
147 | cw.logger.Log("during", "Send", "err", err) | |
148 | } | |
149 | case <-ctx.Done(): | |
150 | return | |
145 | 151 | } |
146 | 152 | } |
147 | 153 | } |
2 | 2 | package cloudwatch2 |
3 | 3 | |
4 | 4 | import ( |
5 | "context" | |
5 | 6 | "math" |
6 | 7 | "sync" |
7 | 8 | "time" |
106 | 107 | } |
107 | 108 | |
108 | 109 | // WriteLoop is a helper method that invokes Send every time the passed |
109 | // channel fires. This method blocks until the channel is closed, so clients | |
110 | // channel fires. This method blocks until ctx is canceled, so clients | |
110 | 111 | // probably want to run it in its own goroutine. For typical usage, create a |
111 | 112 | // time.Ticker and pass its C channel to this method. |
112 | func (cw *CloudWatch) WriteLoop(c <-chan time.Time) { | |
113 | for range c { | |
114 | if err := cw.Send(); err != nil { | |
115 | cw.logger.Log("during", "Send", "err", err) | |
113 | func (cw *CloudWatch) WriteLoop(ctx context.Context, c <-chan time.Time) { | |
114 | for { | |
115 | select { | |
116 | case <-c: | |
117 | if err := cw.Send(); err != nil { | |
118 | cw.logger.Log("during", "Send", "err", err) | |
119 | } | |
120 | case <-ctx.Done(): | |
121 | return | |
116 | 122 | } |
117 | 123 | } |
118 | 124 | } |
10 | 10 | package dogstatsd |
11 | 11 | |
12 | 12 | import ( |
13 | "context" | |
13 | 14 | "fmt" |
14 | 15 | "io" |
15 | 16 | "strings" |
108 | 109 | } |
109 | 110 | |
110 | 111 | // WriteLoop is a helper method that invokes WriteTo to the passed writer every |
111 | // time the passed channel fires. This method blocks until the channel is | |
112 | // closed, so clients probably want to run it in its own goroutine. For typical | |
112 | // time the passed channel fires. This method blocks until ctx is canceled, | |
113 | // so clients probably want to run it in its own goroutine. For typical | |
113 | 114 | // usage, create a time.Ticker and pass its C channel to this method. |
114 | func (d *Dogstatsd) WriteLoop(c <-chan time.Time, w io.Writer) { | |
115 | for range c { | |
116 | if _, err := d.WriteTo(w); err != nil { | |
117 | d.logger.Log("during", "WriteTo", "err", err) | |
115 | func (d *Dogstatsd) WriteLoop(ctx context.Context, c <-chan time.Time, w io.Writer) { | |
116 | for { | |
117 | select { | |
118 | case <-c: | |
119 | if _, err := d.WriteTo(w); err != nil { | |
120 | d.logger.Log("during", "WriteTo", "err", err) | |
121 | } | |
122 | case <-ctx.Done(): | |
123 | return | |
118 | 124 | } |
119 | 125 | } |
120 | 126 | } |
121 | 127 | |
122 | 128 | // SendLoop is a helper method that wraps WriteLoop, passing a managed |
123 | 129 | // connection to the network and address. Like WriteLoop, this method blocks |
124 | // until the channel is closed, so clients probably want to start it in its own | |
130 | // until ctx is canceled, so clients probably want to start it in its own | |
125 | 131 | // goroutine. For typical usage, create a time.Ticker and pass its C channel to |
126 | 132 | // this method. |
127 | func (d *Dogstatsd) SendLoop(c <-chan time.Time, network, address string) { | |
128 | d.WriteLoop(c, conn.NewDefaultManager(network, address, d.logger)) | |
133 | func (d *Dogstatsd) SendLoop(ctx context.Context, c <-chan time.Time, network, address string) { | |
134 | d.WriteLoop(ctx, c, conn.NewDefaultManager(network, address, d.logger)) | |
129 | 135 | } |
130 | 136 | |
131 | 137 | // WriteTo flushes the buffered content of the metrics to the writer, in |
7 | 7 | package graphite |
8 | 8 | |
9 | 9 | import ( |
10 | "context" | |
10 | 11 | "fmt" |
11 | 12 | "io" |
12 | 13 | "sync" |
82 | 83 | } |
83 | 84 | |
84 | 85 | // WriteLoop is a helper method that invokes WriteTo to the passed writer every |
85 | // time the passed channel fires. This method blocks until the channel is | |
86 | // closed, so clients probably want to run it in its own goroutine. For typical | |
86 | // time the passed channel fires. This method blocks until ctx is canceled, | |
87 | // so clients probably want to run it in its own goroutine. For typical | |
87 | 88 | // usage, create a time.Ticker and pass its C channel to this method. |
88 | func (g *Graphite) WriteLoop(c <-chan time.Time, w io.Writer) { | |
89 | for range c { | |
90 | if _, err := g.WriteTo(w); err != nil { | |
91 | g.logger.Log("during", "WriteTo", "err", err) | |
89 | func (g *Graphite) WriteLoop(ctx context.Context, c <-chan time.Time, w io.Writer) { | |
90 | for { | |
91 | select { | |
92 | case <-c: | |
93 | if _, err := g.WriteTo(w); err != nil { | |
94 | g.logger.Log("during", "WriteTo", "err", err) | |
95 | } | |
96 | case <-ctx.Done(): | |
97 | return | |
92 | 98 | } |
93 | 99 | } |
94 | 100 | } |
95 | 101 | |
96 | 102 | // SendLoop is a helper method that wraps WriteLoop, passing a managed |
97 | 103 | // connection to the network and address. Like WriteLoop, this method blocks |
98 | // until the channel is closed, so clients probably want to start it in its own | |
104 | // until ctx is canceled, so clients probably want to start it in its own | |
99 | 105 | // goroutine. For typical usage, create a time.Ticker and pass its C channel to |
100 | 106 | // this method. |
101 | func (g *Graphite) SendLoop(c <-chan time.Time, network, address string) { | |
102 | g.WriteLoop(c, conn.NewDefaultManager(network, address, g.logger)) | |
107 | func (g *Graphite) SendLoop(ctx context.Context, c <-chan time.Time, network, address string) { | |
108 | g.WriteLoop(ctx, c, conn.NewDefaultManager(network, address, g.logger)) | |
103 | 109 | } |
104 | 110 | |
105 | 111 | // WriteTo flushes the buffered content of the metrics to the writer, in |
3 | 3 | package influx |
4 | 4 | |
5 | 5 | import ( |
6 | "context" | |
6 | 7 | "time" |
7 | 8 | |
8 | 9 | influxdb "github.com/influxdata/influxdb1-client/v2" |
87 | 88 | // time the passed channel fires. This method blocks until the channel is |
88 | 89 | // closed, so clients probably want to run it in its own goroutine. For typical |
89 | 90 | // usage, create a time.Ticker and pass its C channel to this method. |
90 | func (in *Influx) WriteLoop(c <-chan time.Time, w BatchPointsWriter) { | |
91 | for range c { | |
92 | if err := in.WriteTo(w); err != nil { | |
93 | in.logger.Log("during", "WriteTo", "err", err) | |
91 | func (in *Influx) WriteLoop(ctx context.Context, c <-chan time.Time, w BatchPointsWriter) { | |
92 | for { | |
93 | select { | |
94 | case <-c: | |
95 | if err := in.WriteTo(w); err != nil { | |
96 | in.logger.Log("during", "WriteTo", "err", err) | |
97 | } | |
98 | case <-ctx.Done(): | |
99 | return | |
94 | 100 | } |
95 | 101 | } |
96 | 102 | } |
10 | 10 | package influxstatsd |
11 | 11 | |
12 | 12 | import ( |
13 | "context" | |
13 | 14 | "fmt" |
14 | 15 | "io" |
15 | 16 | "strings" |
108 | 109 | } |
109 | 110 | |
110 | 111 | // WriteLoop is a helper method that invokes WriteTo to the passed writer every |
111 | // time the passed channel fires. This method blocks until the channel is | |
112 | // closed, so clients probably want to run it in its own goroutine. For typical | |
112 | // time the passed channel fires. This method blocks until ctx is canceled, | |
113 | // so clients probably want to run it in its own goroutine. For typical | |
113 | 114 | // usage, create a time.Ticker and pass its C channel to this method. |
114 | func (d *Influxstatsd) WriteLoop(c <-chan time.Time, w io.Writer) { | |
115 | for range c { | |
116 | if _, err := d.WriteTo(w); err != nil { | |
117 | d.logger.Log("during", "WriteTo", "err", err) | |
115 | func (d *Influxstatsd) WriteLoop(ctx context.Context, c <-chan time.Time, w io.Writer) { | |
116 | for { | |
117 | select { | |
118 | case <-c: | |
119 | if _, err := d.WriteTo(w); err != nil { | |
120 | d.logger.Log("during", "WriteTo", "err", err) | |
121 | } | |
122 | case <-ctx.Done(): | |
123 | return | |
118 | 124 | } |
119 | 125 | } |
120 | 126 | } |
121 | 127 | |
122 | 128 | // SendLoop is a helper method that wraps WriteLoop, passing a managed |
123 | 129 | // connection to the network and address. Like WriteLoop, this method blocks |
124 | // until the channel is closed, so clients probably want to start it in its own | |
130 | // until ctx is canceled, so clients probably want to start it in its own | |
125 | 131 | // goroutine. For typical usage, create a time.Ticker and pass its C channel to |
126 | 132 | // this method. |
127 | func (d *Influxstatsd) SendLoop(c <-chan time.Time, network, address string) { | |
128 | d.WriteLoop(c, conn.NewDefaultManager(network, address, d.logger)) | |
133 | func (d *Influxstatsd) SendLoop(ctx context.Context, c <-chan time.Time, network, address string) { | |
134 | d.WriteLoop(ctx, c, conn.NewDefaultManager(network, address, d.logger)) | |
129 | 135 | } |
130 | 136 | |
131 | 137 | // WriteTo flushes the buffered content of the metrics to the writer, in |
13 | 13 | // case "statsd": |
14 | 14 | // s := statsd.New(...) |
15 | 15 | // t := time.NewTicker(5*time.Second) |
16 | // go s.SendLoop(t.C, "tcp", "statsd.local:8125") | |
16 | // go s.SendLoop(ctx, t.C, "tcp", "statsd.local:8125") | |
17 | 17 | // latency = s.NewHistogram(...) |
18 | 18 | // requests = s.NewCounter(...) |
19 | 19 | // default: |
8 | 8 | package statsd |
9 | 9 | |
10 | 10 | import ( |
11 | "context" | |
11 | 12 | "fmt" |
12 | 13 | "io" |
13 | 14 | "time" |
88 | 89 | } |
89 | 90 | |
90 | 91 | // WriteLoop is a helper method that invokes WriteTo to the passed writer every |
91 | // time the passed channel fires. This method blocks until the channel is | |
92 | // closed, so clients probably want to run it in its own goroutine. For typical | |
92 | // time the passed channel fires. This method blocks until ctx is canceled, | |
93 | // so clients probably want to run it in its own goroutine. For typical | |
93 | 94 | // usage, create a time.Ticker and pass its C channel to this method. |
94 | func (s *Statsd) WriteLoop(c <-chan time.Time, w io.Writer) { | |
95 | for range c { | |
96 | if _, err := s.WriteTo(w); err != nil { | |
97 | s.logger.Log("during", "WriteTo", "err", err) | |
95 | func (s *Statsd) WriteLoop(ctx context.Context, c <-chan time.Time, w io.Writer) { | |
96 | for { | |
97 | select { | |
98 | case <-c: | |
99 | if _, err := s.WriteTo(w); err != nil { | |
100 | s.logger.Log("during", "WriteTo", "err", err) | |
101 | } | |
102 | case <-ctx.Done(): | |
103 | return | |
98 | 104 | } |
99 | 105 | } |
100 | 106 | } |
101 | 107 | |
102 | 108 | // SendLoop is a helper method that wraps WriteLoop, passing a managed |
103 | 109 | // connection to the network and address. Like WriteLoop, this method blocks |
104 | // until the channel is closed, so clients probably want to start it in its own | |
110 | // until ctx is canceled, so clients probably want to start it in its own | |
105 | 111 | // goroutine. For typical usage, create a time.Ticker and pass its C channel to |
106 | 112 | // this method. |
107 | func (s *Statsd) SendLoop(c <-chan time.Time, network, address string) { | |
108 | s.WriteLoop(c, conn.NewDefaultManager(network, address, s.logger)) | |
113 | func (s *Statsd) SendLoop(ctx context.Context, c <-chan time.Time, network, address string) { | |
114 | s.WriteLoop(ctx, c, conn.NewDefaultManager(network, address, s.logger)) | |
109 | 115 | } |
110 | 116 | |
111 | 117 | // WriteTo flushes the buffered content of the metrics to the writer, in |