Skip to content

Commit f400e7c

Browse files
authored
Add event.dropped and event.age metrics (#52)
These provide more insight into the queued asynchronous scheduler.
1 parent 8e89342 commit f400e7c

File tree

2 files changed

+30
-5
lines changed

2 files changed

+30
-5
lines changed

README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ logic of your application.
1313
* [Asynchronous Dispatch](#asynchronous-dispatch)
1414
* [Structured Logging](#structured-logging)
1515
* [GitHub Clients](#github-clients)
16-
+ [Metrics](#metrics)
16+
* [Metrics](#metrics)
1717
* [Background Jobs and Multi-Organization Operations](#background-jobs-and-multi-organization-operations)
1818
* [OAuth2](#oauth2)
1919
* [Stability and Versioning Guarantees](#stability-and-versioning-guarantees)
@@ -203,7 +203,7 @@ baseHandler, err := githubapp.NewDefaultCachingClientCreator(
203203
)
204204
```
205205

206-
### Metrics
206+
## Metrics
207207

208208
`go-githubapp` uses [rcrowley/go-metrics][] to provide metrics. GitHub clients
209209
emit the metrics below if configured with the `githubapp.ClientMetrics`
@@ -220,13 +220,15 @@ middleware.
220220
| `github.rate.limit[installation:<id>]` | `gauge` | the maximum number of requests permitted to make per hour, tagged with the installation id |
221221
| `github.rate.remaining[installation:<id>]` | `gauge` | the number of requests remaining in the current rate limit window, tagged with the installation id |
222222

223-
If using [asynchronous dispatch](#asynchronous-dispatch) and the `githubapp.WithSchedulingMetrics` option
224-
is set, these metrics are emitted:
223+
When using [asynchronous dispatch](#asynchronous-dispatch), the
224+
`githubapp.WithSchedulingMetrics` option emits the following metrics:
225225

226226
| metric name | type | definition |
227227
| ----------- | ---- | ---------- |
228228
| `github.event.queue` | `gauge` | the number of queued unprocessed event |
229229
| `github.event.workers` | `gauge` | the number of workers actively processing events |
230+
| `github.event.dropped` | `counter` | the number events dropped due to limited queue capacity |
231+
| `github.event.age` | `histogram` | the age (queue time) in milliseconds of events at processing time |
230232

231233
Note that metrics need to be published in order to be useful. Several
232234
[publishing options][] are available or you can implement your own.

githubapp/scheduler.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"context"
1919
"fmt"
2020
"sync/atomic"
21+
"time"
2122

2223
"github.com/pkg/errors"
2324
"github.com/rcrowley/go-metrics"
@@ -27,6 +28,14 @@ import (
2728
const (
2829
MetricsKeyQueueLength = "github.event.queued"
2930
MetricsKeyActiveWorkers = "github.event.workers"
31+
MetricsKeyEventAge = "github.event.age"
32+
MetricsKeyDroppedEvents = "github.event.dropped"
33+
)
34+
35+
const (
36+
// values from metrics.NewTimer, which match those used by UNIX load averages
37+
histogramReservoirSize = 1028
38+
histogramAlpha = 0.015
3039
)
3140

3241
var (
@@ -119,11 +128,16 @@ func WithSchedulingMetrics(r metrics.Registry) SchedulerOption {
119128
metrics.NewRegisteredFunctionalGauge(MetricsKeyActiveWorkers, r, func() int64 {
120129
return atomic.LoadInt64(&s.activeWorkers)
121130
})
131+
132+
sample := metrics.NewExpDecaySample(histogramReservoirSize, histogramAlpha)
133+
s.eventAge = metrics.NewRegisteredHistogram(MetricsKeyEventAge, r, sample)
134+
s.dropped = metrics.NewRegisteredCounter(MetricsKeyDroppedEvents, r)
122135
}
123136
}
124137

125138
type queueDispatch struct {
126139
ctx context.Context
140+
t time.Time
127141
d Dispatch
128142
}
129143

@@ -134,6 +148,9 @@ type scheduler struct {
134148

135149
activeWorkers int64
136150
queue chan queueDispatch
151+
152+
eventAge metrics.Histogram
153+
dropped metrics.Counter
137154
}
138155

139156
func (s *scheduler) safeExecute(ctx context.Context, d Dispatch) {
@@ -224,6 +241,9 @@ func QueueAsyncScheduler(queueSize int, workers int, opts ...SchedulerOption) Sc
224241
for i := 0; i < workers; i++ {
225242
go func() {
226243
for d := range s.queue {
244+
if s.eventAge != nil {
245+
s.eventAge.Update(time.Since(d.t).Milliseconds())
246+
}
227247
s.safeExecute(d.ctx, d.d)
228248
}
229249
}()
@@ -238,8 +258,11 @@ type queueScheduler struct {
238258

239259
func (s *queueScheduler) Schedule(ctx context.Context, d Dispatch) error {
240260
select {
241-
case s.queue <- queueDispatch{ctx: s.derive(ctx), d: d}:
261+
case s.queue <- queueDispatch{ctx: s.derive(ctx), t: time.Now(), d: d}:
242262
default:
263+
if s.dropped != nil {
264+
s.dropped.Inc(1)
265+
}
243266
return ErrCapacityExceeded
244267
}
245268
return nil

0 commit comments

Comments
 (0)