mirror of
https://github.com/prometheus/alertmanager.git
synced 2026-02-05 15:45:34 +01:00
Merge pull request #4355 from eyazici90/local/slack-timeout
feat: add timeout option for slack notifier
This commit is contained in:
@@ -512,6 +512,9 @@ type SlackConfig struct {
|
||||
LinkNames bool `yaml:"link_names" json:"link_names,omitempty"`
|
||||
MrkdwnIn []string `yaml:"mrkdwn_in,omitempty" json:"mrkdwn_in,omitempty"`
|
||||
Actions []*SlackAction `yaml:"actions,omitempty" json:"actions,omitempty"`
|
||||
// Timeout is the maximum time allowed to invoke the slack. Setting this to 0
|
||||
// does not impose a timeout.
|
||||
Timeout time.Duration `yaml:"timeout" json:"timeout"`
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
|
||||
@@ -1460,6 +1460,12 @@ fields:
|
||||
|
||||
# The HTTP client's configuration.
|
||||
[ http_config: <http_config> | default = global.http_config ]
|
||||
|
||||
# The maximum time to wait for a slack request to complete, before failing the
|
||||
# request and allowing it to be retried. The default value of 0s indicates that
|
||||
# no timeout should be applied.
|
||||
# NOTE: This will have no effect if set higher than the group_interval.
|
||||
[ timeout: <duration> | default = 0s ]
|
||||
```
|
||||
|
||||
#### `<action_config>`
|
||||
|
||||
@@ -204,8 +204,17 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error)
|
||||
u = strings.TrimSpace(string(content))
|
||||
}
|
||||
|
||||
if n.conf.Timeout > 0 {
|
||||
postCtx, cancel := context.WithTimeoutCause(ctx, n.conf.Timeout, fmt.Errorf("configured slack timeout reached (%s)", n.conf.Timeout))
|
||||
defer cancel()
|
||||
ctx = postCtx
|
||||
}
|
||||
|
||||
resp, err := n.postJSONFunc(ctx, n.client, u, &buf)
|
||||
if err != nil {
|
||||
if ctx.Err() != nil {
|
||||
err = fmt.Errorf("%w: %w", err, context.Cause(ctx))
|
||||
}
|
||||
return true, notify.RedactURL(err)
|
||||
}
|
||||
defer notify.Drain(resp)
|
||||
|
||||
@@ -234,3 +234,56 @@ func TestNotifier_Notify_WithReason(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSlackTimeout(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
latency time.Duration
|
||||
timeout time.Duration
|
||||
wantErr bool
|
||||
}{
|
||||
"success": {latency: 100 * time.Millisecond, timeout: 120 * time.Millisecond, wantErr: false},
|
||||
"error": {latency: 100 * time.Millisecond, timeout: 80 * time.Millisecond, wantErr: true},
|
||||
}
|
||||
|
||||
for name, tt := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
u, _ := url.Parse("https://slack.com/post.Message")
|
||||
notifier, err := New(
|
||||
&config.SlackConfig{
|
||||
NotifierConfig: config.NotifierConfig{},
|
||||
HTTPConfig: &commoncfg.HTTPClientConfig{},
|
||||
APIURL: &config.SecretURL{URL: u},
|
||||
Channel: "channelname",
|
||||
Timeout: tt.timeout,
|
||||
},
|
||||
test.CreateTmpl(t),
|
||||
promslog.NewNopLogger(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
notifier.postJSONFunc = func(ctx context.Context, client *http.Client, url string, body io.Reader) (*http.Response, error) {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
case <-time.After(tt.latency):
|
||||
resp := httptest.NewRecorder()
|
||||
resp.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
resp.WriteHeader(http.StatusOK)
|
||||
resp.WriteString(`{"ok":true}`)
|
||||
|
||||
return resp.Result(), nil
|
||||
}
|
||||
}
|
||||
ctx := context.Background()
|
||||
ctx = notify.WithGroupKey(ctx, "1")
|
||||
|
||||
alert := &types.Alert{
|
||||
Alert: model.Alert{
|
||||
StartsAt: time.Now(),
|
||||
EndsAt: time.Now().Add(time.Hour),
|
||||
},
|
||||
}
|
||||
_, err = notifier.Notify(ctx, alert)
|
||||
require.Equal(t, tt.wantErr, err != nil)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user