Skip to content

Commit 264e720

Browse files
committed
feat(threadwinds-ingestion): implement infinite retry with exponential backoff
1 parent 72fcfb0 commit 264e720

File tree

2 files changed

+30
-25
lines changed

2 files changed

+30
-25
lines changed

threadwinds-ingestion/main.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,7 @@ func main() {
7171
return nil
7272
}
7373

74-
err = utils.InfiniteRetryIfXError(registerFunc, "404", "Not Found", "connection refused")
75-
if err != nil {
76-
catcher.Error("failed to register in ThreadWinds Platform after retries", err, nil)
77-
os.Exit(1)
78-
}
74+
utils.InfiniteRetry(registerFunc, "ThreadWinds registration")
7975

8076
catcher.Info("ThreadWinds registration successful", nil)
8177

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,48 @@
11
package utils
22

33
import (
4-
"strings"
4+
"fmt"
55
"time"
66

77
"github.com/threatwinds/go-sdk/catcher"
88
)
99

1010
const (
11-
wait = 5 * time.Second
11+
retryInitialBackoff = 5 * time.Second
12+
retryMaxBackoff = 2 * time.Minute
13+
retryBackoffMultiplier = 2.0
14+
retryLogInterval = 10
1215
)
1316

14-
func InfiniteRetryIfXError(f func() error, exceptions ...string) error {
15-
var xErrorWasLogged bool
17+
func InfiniteRetry(f func() error, operationName string) {
18+
attempt := 0
19+
currentBackoff := retryInitialBackoff
20+
21+
catcher.Info(fmt.Sprintf("Starting %s with infinite retry and exponential backoff", operationName), map[string]any{
22+
"initial_backoff": retryInitialBackoff.String(),
23+
"max_backoff": retryMaxBackoff.String(),
24+
})
1625

1726
for {
27+
attempt++
1828
err := f()
19-
if err != nil && is(err, exceptions...) {
20-
if !xErrorWasLogged {
21-
_ = catcher.Error("An error occurred (%s), will keep retrying indefinitely...", err, nil)
22-
xErrorWasLogged = true
23-
}
24-
time.Sleep(wait)
25-
continue
26-
}
2729

28-
return err
29-
}
30-
}
30+
if err == nil {
31+
catcher.Info(fmt.Sprintf("%s completed successfully", operationName), map[string]any{
32+
"attempts": attempt,
33+
})
34+
return
35+
}
3136

32-
func is(e error, args ...string) bool {
33-
for _, arg := range args {
34-
if strings.Contains(e.Error(), arg) {
35-
return true
37+
if attempt == 1 || attempt%retryLogInterval == 0 {
38+
_ = catcher.Error(fmt.Sprintf("%s failed, will retry indefinitely...", operationName), err, map[string]any{
39+
"attempt": attempt,
40+
"next_retry_in": currentBackoff.String(),
41+
})
3642
}
43+
44+
time.Sleep(currentBackoff)
45+
46+
currentBackoff = min(time.Duration(float64(currentBackoff)*retryBackoffMultiplier), retryMaxBackoff)
3747
}
38-
return false
3948
}

0 commit comments

Comments
 (0)