Store a target's number of delivery attempts, at least one (closes #540)
check / check (push) Canceled after 0s

Target.MaxRetries (max_retries) becomes Target.MaxAttempts
(max_attempts), and the form field, parser and ceiling are renamed to
match. 1 is a single attempt with no circuit breaker; above 1 retries
behind the breaker up to that many attempts. Both target forms refuse
0 and less; a blank field on the add target form gives 1, and on the
edit form keeps the stored value. The target page shows the plain
number, and the README's two paragraphs on 0 against 1 become one
sentence.

Model: opus-5-5
This commit is contained in:
2026-10-15 11:34:18 +00:00
parent c0f7cc29fd
commit 14a38df093
37 changed files with 843 additions and 716 deletions
+9 -14
View File
@@ -120,8 +120,8 @@ func unavailableConfigFields() []ConfigField {
}
// slackConfigFields describes a Slack target: its masked
// webhook URL and its retry count. Only the masked URL is
// shown; the full URL is the credential.
// webhook URL and its number of delivery attempts. Only the
// masked URL is shown; the full URL is the credential.
func slackConfigFields(t *database.Target) []ConfigField {
cfg, err := parseSlackConfig(t.Config)
if err != nil {
@@ -131,7 +131,7 @@ func slackConfigFields(t *database.Target) []ConfigField {
return []ConfigField{{
Label: "Webhook URL",
Value: cfg.MaskedWebhookURL(),
}, maxRetriesField(t)}
}, maxAttemptsField(t)}
}
// httpConfigFields describes an HTTP target: its destination
@@ -178,23 +178,18 @@ func httpConfigFields(t *database.Target) []ConfigField {
})
}
fields = append(fields, maxRetriesField(t))
fields = append(fields, maxAttemptsField(t))
return fields
}
// maxRetriesField describes a target's retry count, which lives
// on the target row rather than in its configuration blob. A
// stored 0 makes a single attempt, so it is shown as 1.
func maxRetriesField(t *database.Target) ConfigField {
attempts := strconv.Itoa(t.MaxRetries)
if t.MaxRetries == 0 {
attempts = "1 (fire-and-forget: no retries, no circuit breaker)"
}
// maxAttemptsField describes a target's number of delivery
// attempts, which lives on the target row rather than in its
// configuration blob.
func maxAttemptsField(t *database.Target) ConfigField {
return ConfigField{
Label: "Delivery attempts",
Value: attempts,
Value: strconv.Itoa(t.MaxAttempts),
}
}