mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-06-13 12:10:40 +00:00
bdb60de7ae
- Update go.mod and Dockerfile to Go 1.26 - Apply `go fix ./...` stdlib modernizations across 170+ files - Add `go fix` to post-implementation checklist in CLAUDE.md - Fix go fix misapplied rewrite in loop_history.go
68 lines
1.9 KiB
Go
68 lines
1.9 KiB
Go
package cron
|
|
|
|
import (
|
|
"math/rand/v2"
|
|
"time"
|
|
)
|
|
|
|
// RetryConfig controls exponential backoff retry for failed cron jobs.
|
|
type RetryConfig struct {
|
|
MaxRetries int // max retry attempts (default 3, 0 = no retry)
|
|
BaseDelay time.Duration // initial backoff delay (default 2s)
|
|
MaxDelay time.Duration // maximum backoff delay (default 30s)
|
|
}
|
|
|
|
// DefaultRetryConfig returns sensible defaults.
|
|
func DefaultRetryConfig() RetryConfig {
|
|
return RetryConfig{
|
|
MaxRetries: 3,
|
|
BaseDelay: 2 * time.Second,
|
|
MaxDelay: 30 * time.Second,
|
|
}
|
|
}
|
|
|
|
// ExecuteWithRetry runs fn, retrying on error with exponential backoff + jitter.
|
|
// Returns the first successful result or the last error after all retries.
|
|
func ExecuteWithRetry(fn func() (string, error), cfg RetryConfig) (result string, attempts int, err error) {
|
|
for attempt := 0; attempt <= cfg.MaxRetries; attempt++ {
|
|
result, err = fn()
|
|
if err == nil {
|
|
return result, attempt + 1, nil
|
|
}
|
|
|
|
if attempt < cfg.MaxRetries {
|
|
delay := backoffWithJitter(cfg.BaseDelay, cfg.MaxDelay, attempt)
|
|
time.Sleep(delay)
|
|
}
|
|
}
|
|
return "", cfg.MaxRetries + 1, err
|
|
}
|
|
|
|
// backoffWithJitter computes delay = min(base * 2^attempt, max) + jitter(±25%).
|
|
func backoffWithJitter(base, max time.Duration, attempt int) time.Duration {
|
|
delay := min(
|
|
// base * 2^attempt
|
|
base<<uint(attempt), max)
|
|
|
|
// Jitter: ±25% of delay
|
|
quarter := delay / 4
|
|
if quarter > 0 {
|
|
jitter := time.Duration(rand.Int64N(int64(quarter*2))) - quarter
|
|
delay += jitter
|
|
}
|
|
|
|
return delay
|
|
}
|
|
|
|
// maxOutputBytes is the truncation limit for cron job output (16KB).
|
|
// Prevents storing excessively large results in run logs.
|
|
const maxOutputBytes = 16 * 1024
|
|
|
|
// TruncateOutput truncates output to maxOutputBytes, appending "..." if truncated.
|
|
func TruncateOutput(s string) string {
|
|
if len(s) <= maxOutputBytes {
|
|
return s
|
|
}
|
|
return s[:maxOutputBytes] + "...[truncated]"
|
|
}
|