Skip to content

Commit 9ec88ae

Browse files
authored
Merge pull request #4355 from eyazici90/local/slack-timeout
feat: add timeout option for slack notifier
2 parents d484571 + e8f6948 commit 9ec88ae

File tree

4 files changed

+71
-0
lines changed

4 files changed

+71
-0
lines changed

config/notifiers.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,9 @@ type SlackConfig struct {
512512
LinkNames bool `yaml:"link_names" json:"link_names,omitempty"`
513513
MrkdwnIn []string `yaml:"mrkdwn_in,omitempty" json:"mrkdwn_in,omitempty"`
514514
Actions []*SlackAction `yaml:"actions,omitempty" json:"actions,omitempty"`
515+
// Timeout is the maximum time allowed to invoke the slack. Setting this to 0
516+
// does not impose a timeout.
517+
Timeout time.Duration `yaml:"timeout" json:"timeout"`
515518
}
516519

517520
// UnmarshalYAML implements the yaml.Unmarshaler interface.

docs/configuration.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1460,6 +1460,12 @@ fields:
14601460
14611461
# The HTTP client's configuration.
14621462
[ http_config: <http_config> | default = global.http_config ]
1463+
1464+
# The maximum time to wait for a slack request to complete, before failing the
1465+
# request and allowing it to be retried. The default value of 0s indicates that
1466+
# no timeout should be applied.
1467+
# NOTE: This will have no effect if set higher than the group_interval.
1468+
[ timeout: <duration> | default = 0s ]
14631469
```
14641470

14651471
#### `<action_config>`

notify/slack/slack.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,17 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error)
204204
u = strings.TrimSpace(string(content))
205205
}
206206

207+
if n.conf.Timeout > 0 {
208+
postCtx, cancel := context.WithTimeoutCause(ctx, n.conf.Timeout, fmt.Errorf("configured slack timeout reached (%s)", n.conf.Timeout))
209+
defer cancel()
210+
ctx = postCtx
211+
}
212+
207213
resp, err := n.postJSONFunc(ctx, n.client, u, &buf)
208214
if err != nil {
215+
if ctx.Err() != nil {
216+
err = fmt.Errorf("%w: %w", err, context.Cause(ctx))
217+
}
209218
return true, notify.RedactURL(err)
210219
}
211220
defer notify.Drain(resp)

notify/slack/slack_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,3 +234,56 @@ func TestNotifier_Notify_WithReason(t *testing.T) {
234234
})
235235
}
236236
}
237+
238+
func TestSlackTimeout(t *testing.T) {
239+
tests := map[string]struct {
240+
latency time.Duration
241+
timeout time.Duration
242+
wantErr bool
243+
}{
244+
"success": {latency: 100 * time.Millisecond, timeout: 120 * time.Millisecond, wantErr: false},
245+
"error": {latency: 100 * time.Millisecond, timeout: 80 * time.Millisecond, wantErr: true},
246+
}
247+
248+
for name, tt := range tests {
249+
t.Run(name, func(t *testing.T) {
250+
u, _ := url.Parse("https://slack.com/post.Message")
251+
notifier, err := New(
252+
&config.SlackConfig{
253+
NotifierConfig: config.NotifierConfig{},
254+
HTTPConfig: &commoncfg.HTTPClientConfig{},
255+
APIURL: &config.SecretURL{URL: u},
256+
Channel: "channelname",
257+
Timeout: tt.timeout,
258+
},
259+
test.CreateTmpl(t),
260+
promslog.NewNopLogger(),
261+
)
262+
require.NoError(t, err)
263+
notifier.postJSONFunc = func(ctx context.Context, client *http.Client, url string, body io.Reader) (*http.Response, error) {
264+
select {
265+
case <-ctx.Done():
266+
return nil, ctx.Err()
267+
case <-time.After(tt.latency):
268+
resp := httptest.NewRecorder()
269+
resp.Header().Set("Content-Type", "application/json; charset=utf-8")
270+
resp.WriteHeader(http.StatusOK)
271+
resp.WriteString(`{"ok":true}`)
272+
273+
return resp.Result(), nil
274+
}
275+
}
276+
ctx := context.Background()
277+
ctx = notify.WithGroupKey(ctx, "1")
278+
279+
alert := &types.Alert{
280+
Alert: model.Alert{
281+
StartsAt: time.Now(),
282+
EndsAt: time.Now().Add(time.Hour),
283+
},
284+
}
285+
_, err = notifier.Notify(ctx, alert)
286+
require.Equal(t, tt.wantErr, err != nil)
287+
})
288+
}
289+
}

0 commit comments

Comments
 (0)