Skip to content

Commit ca9ed08

Browse files
authored
Merge pull request #4354 from eyazici90/local/timeoutt
feat: add timeout option for pagerduty notifier
2 parents 9ec88ae + 8da7f29 commit ca9ed08

File tree

4 files changed

+93
-2
lines changed

4 files changed

+93
-2
lines changed

config/notifiers.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,9 @@ type PagerdutyConfig struct {
352352
Class string `yaml:"class,omitempty" json:"class,omitempty"`
353353
Component string `yaml:"component,omitempty" json:"component,omitempty"`
354354
Group string `yaml:"group,omitempty" json:"group,omitempty"`
355+
// Timeout is the maximum time allowed to invoke the pagerduty. Setting this to 0
356+
// does not impose a timeout.
357+
Timeout time.Duration `yaml:"timeout" json:"timeout"`
355358
}
356359

357360
// PagerdutyLink is a link.

docs/configuration.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1276,6 +1276,12 @@ links:
12761276

12771277
# The HTTP client's configuration.
12781278
[ http_config: <http_config> | default = global.http_config ]
1279+
1280+
# The maximum time to wait for a pagerduty request to complete, before failing the
1281+
# request and allowing it to be retried. The default value of 0s indicates that
1282+
# no timeout should be applied.
1283+
# NOTE: This will have no effect if set higher than the group_interval.
1284+
[ timeout: <duration> | default = 0s ]
12791285
```
12801286
12811287
#### `<image_config>`

notify/pagerduty/pagerduty.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -329,10 +329,24 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error)
329329
details[k] = detail
330330
}
331331

332+
if n.conf.Timeout > 0 {
333+
nfCtx, cancel := context.WithTimeoutCause(ctx, n.conf.Timeout, fmt.Errorf("configured pagerduty timeout reached (%s)", n.conf.Timeout))
334+
defer cancel()
335+
ctx = nfCtx
336+
}
337+
338+
nf := n.notifyV2
332339
if n.apiV1 != "" {
333-
return n.notifyV1(ctx, eventType, key, data, details, as...)
340+
nf = n.notifyV1
341+
}
342+
retry, err := nf(ctx, eventType, key, data, details, as...)
343+
if err != nil {
344+
if ctx.Err() != nil {
345+
err = fmt.Errorf("%w: %w", err, context.Cause(ctx))
346+
}
347+
return retry, err
334348
}
335-
return n.notifyV2(ctx, eventType, key, data, details, as...)
349+
return retry, nil
336350
}
337351

338352
func errDetails(status int, body io.Reader) string {

notify/pagerduty/pagerduty_test.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,3 +496,71 @@ func TestPagerDutyEmptySrcHref(t *testing.T) {
496496
}...)
497497
require.NoError(t, err)
498498
}
499+
500+
func TestPagerDutyTimeout(t *testing.T) {
501+
type pagerDutyEvent struct {
502+
RoutingKey string `json:"routing_key"`
503+
EventAction string `json:"event_action"`
504+
DedupKey string `json:"dedup_key"`
505+
Payload pagerDutyPayload `json:"payload"`
506+
Images []pagerDutyImage
507+
Links []pagerDutyLink
508+
}
509+
510+
tests := map[string]struct {
511+
latency time.Duration
512+
timeout time.Duration
513+
wantErr bool
514+
}{
515+
"success": {latency: 100 * time.Millisecond, timeout: 120 * time.Millisecond, wantErr: false},
516+
"error": {latency: 100 * time.Millisecond, timeout: 80 * time.Millisecond, wantErr: true},
517+
}
518+
519+
for name, tt := range tests {
520+
t.Run(name, func(t *testing.T) {
521+
522+
srv := httptest.NewServer(http.HandlerFunc(
523+
func(w http.ResponseWriter, r *http.Request) {
524+
decoder := json.NewDecoder(r.Body)
525+
var event pagerDutyEvent
526+
if err := decoder.Decode(&event); err != nil {
527+
panic(err)
528+
}
529+
530+
if event.RoutingKey == "" || event.EventAction == "" {
531+
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
532+
return
533+
}
534+
time.Sleep(tt.latency)
535+
},
536+
))
537+
defer srv.Close()
538+
u, err := url.Parse(srv.URL)
539+
require.NoError(t, err)
540+
541+
cfg := config.PagerdutyConfig{
542+
HTTPConfig: &commoncfg.HTTPClientConfig{},
543+
RoutingKey: config.Secret("01234567890123456789012345678901"),
544+
URL: &config.URL{URL: u},
545+
Timeout: tt.timeout,
546+
}
547+
548+
pd, err := New(&cfg, test.CreateTmpl(t), promslog.NewNopLogger())
549+
require.NoError(t, err)
550+
551+
ctx := context.Background()
552+
ctx = notify.WithGroupKey(ctx, "1")
553+
alert := &types.Alert{
554+
Alert: model.Alert{
555+
Labels: model.LabelSet{
556+
"lbl1": "val1",
557+
},
558+
StartsAt: time.Now(),
559+
EndsAt: time.Now().Add(time.Hour),
560+
},
561+
}
562+
_, err = pd.Notify(ctx, alert)
563+
require.Equal(t, tt.wantErr, err != nil)
564+
})
565+
}
566+
}

0 commit comments

Comments
 (0)