• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

supabase / cli / 19032133102

03 Nov 2025 10:55AM UTC coverage: 54.585% (-0.1%) from 54.699%
19032133102

Pull #4394

github

web-flow
Merge 3b6ecd499 into df557dc33
Pull Request #4394: feat(cli): add concurrent images pulling

213 of 384 new or added lines in 3 files covered. (55.47%)

16 existing lines in 2 files now uncovered.

6584 of 12062 relevant lines covered (54.58%)

6.36 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

47.62
/internal/utils/retry.go
1
package utils
2

3
import (
4
        "context"
5
        "fmt"
6
        "os"
7
        "time"
8

9
        "github.com/cenkalti/backoff/v4"
10
        "github.com/go-errors/errors"
11
)
12

13
const maxRetries = 8
14

15
func NewBackoffPolicy(ctx context.Context) backoff.BackOffContext {
×
16
        b := backoff.NewExponentialBackOff(backoff.WithInitialInterval(3 * time.Second))
×
17
        return backoff.WithContext(backoff.WithMaxRetries(b, maxRetries), ctx)
×
18
}
×
19

20
func NewErrorCallback(callbacks ...func(attempt uint) error) backoff.Notify {
×
21
        failureCount := uint(0)
×
22
        logger := GetDebugLogger()
×
23
        return func(err error, d time.Duration) {
×
24
                failureCount += 1
×
25
                if failureCount*3 > maxRetries {
×
26
                        logger = os.Stderr
×
27
                }
×
28
                for _, cb := range callbacks {
×
29
                        if err := cb(failureCount); err != nil {
×
30
                                fmt.Fprintln(logger, err)
×
31
                        }
×
32
                }
33
                fmt.Fprintln(logger, err)
×
34
                fmt.Fprintf(logger, "Retry (%d/%d): ", failureCount, maxRetries)
×
35
        }
36
}
37

38
// RetryWithExponentialBackoff executes fn with exponential backoff retry logic.
39
// maxRetries is the maximum number of retries (so total attempts = maxRetries + 1).
40
// onRetry is called before each retry with the retry attempt number (0-indexed) and backoff duration.
41
// If onRetry is nil, no retry notification is sent.
42
// isRetryable is an optional function that determines if an error should be retried.
43
// If isRetryable is nil or returns true, the error will be retried (subject to maxRetries).
44
// If isRetryable returns false, the error will be returned immediately without retrying.
45
// Exponential backoff: 1s, 2s, 4s, 8s, 16s, 32s for retries 0-5.
46
func RetryWithExponentialBackoff(ctx context.Context, fn func() error, maxRetries uint, onRetry func(attempt uint, backoff time.Duration), isRetryable func(error) bool) error {
2✔
47
        var lastErr error
2✔
48
        for attempt := uint(0); attempt <= maxRetries; attempt++ {
6✔
49
                err := fn()
4✔
50
                if err == nil {
5✔
51
                        return nil
1✔
52
                }
1✔
53
                lastErr = err
3✔
54

3✔
55
                // Don't retry if context is canceled
3✔
56
                if errors.Is(ctx.Err(), context.Canceled) {
3✔
NEW
57
                        return lastErr
×
NEW
58
                }
×
59

60
                // Don't retry if the error is not retryable
61
                if isRetryable != nil && !isRetryable(lastErr) {
4✔
62
                        return lastErr
1✔
63
                }
1✔
64

65
                // Don't retry if we've exhausted all retries
66
                if attempt >= maxRetries {
2✔
NEW
67
                        break
×
68
                }
69

70
                // Calculate exponential backoff: 1s, 2s, 4s, 8s, 16s, 32s
71
                backoff := time.Duration(1<<attempt) * time.Second
2✔
72
                if onRetry != nil {
4✔
73
                        onRetry(attempt, backoff)
2✔
74
                }
2✔
75
                time.Sleep(backoff)
2✔
76
        }
NEW
77
        return lastErr
×
78
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc