Skip to content

Commit 27ca207

Browse files
authored
fix: retry on error listing functions (#3490)
* fix: retry on error listing functions * chore: update unit tests
1 parent d745c72 commit 27ca207

File tree

2 files changed

+25
-19
lines changed

2 files changed

+25
-19
lines changed

pkg/function/batch.go

+18-8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"context"
66
"fmt"
77
"io"
8+
"net/http"
89
"os"
910
"strings"
1011
"time"
@@ -22,19 +23,28 @@ const (
2223
)
2324

2425
func (s *EdgeRuntimeAPI) UpsertFunctions(ctx context.Context, functionConfig config.FunctionConfig, filter ...func(string) bool) error {
25-
var result []api.FunctionResponse
26-
if resp, err := s.client.V1ListAllFunctionsWithResponse(ctx, s.project); err != nil {
27-
return errors.Errorf("failed to list functions: %w", err)
28-
} else if resp.JSON200 == nil {
29-
return errors.Errorf("unexpected list functions status %d: %s", resp.StatusCode(), string(resp.Body))
30-
} else {
31-
result = *resp.JSON200
26+
policy := backoff.WithContext(backoff.WithMaxRetries(backoff.NewExponentialBackOff(), maxRetries), ctx)
27+
result, err := backoff.RetryWithData(func() ([]api.FunctionResponse, error) {
28+
resp, err := s.client.V1ListAllFunctionsWithResponse(ctx, s.project)
29+
if err != nil {
30+
return nil, errors.Errorf("failed to list functions: %w", err)
31+
} else if resp.JSON200 == nil {
32+
err = errors.Errorf("unexpected list functions status %d: %s", resp.StatusCode(), string(resp.Body))
33+
if resp.StatusCode() < http.StatusInternalServerError {
34+
err = &backoff.PermanentError{Err: err}
35+
}
36+
return nil, err
37+
}
38+
return *resp.JSON200, nil
39+
}, policy)
40+
if err != nil {
41+
return err
3242
}
43+
policy.Reset()
3344
exists := make(map[string]struct{}, len(result))
3445
for _, f := range result {
3546
exists[f.Slug] = struct{}{}
3647
}
37-
policy := backoff.WithContext(backoff.WithMaxRetries(backoff.NewExponentialBackOff(), maxRetries), ctx)
3848
var toUpdate []api.BulkUpdateFunctionBody
3949
OUTER:
4050
for slug, function := range functionConfig {

pkg/function/batch_test.go

+7-11
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/h2non/gock"
1111
"github.com/stretchr/testify/assert"
1212
"github.com/stretchr/testify/require"
13+
"github.com/supabase/cli/internal/testing/apitest"
1314
"github.com/supabase/cli/pkg/api"
1415
"github.com/supabase/cli/pkg/config"
1516
)
@@ -41,28 +42,23 @@ func TestUpsertFunctions(t *testing.T) {
4142
era.eszip = &MockBundler{}
4243
})
4344

44-
t.Run("throws error on network failure", func(t *testing.T) {
45+
t.Run("retries on network failure", func(t *testing.T) {
4546
// Setup mock api
4647
defer gock.OffAll()
4748
gock.New(mockApiHost).
4849
Get("/v1/projects/" + mockProject + "/functions").
4950
ReplyError(errors.New("network error"))
50-
// Run test
51-
err := client.UpsertFunctions(context.Background(), nil)
52-
// Check error
53-
assert.ErrorContains(t, err, "network error")
54-
})
55-
56-
t.Run("throws error on service unavailable", func(t *testing.T) {
57-
// Setup mock api
58-
defer gock.OffAll()
5951
gock.New(mockApiHost).
6052
Get("/v1/projects/" + mockProject + "/functions").
6153
Reply(http.StatusServiceUnavailable)
54+
gock.New(mockApiHost).
55+
Get("/v1/projects/" + mockProject + "/functions").
56+
Reply(http.StatusBadRequest)
6257
// Run test
6358
err := client.UpsertFunctions(context.Background(), nil)
6459
// Check error
65-
assert.ErrorContains(t, err, "unexpected list functions status 503:")
60+
assert.ErrorContains(t, err, "unexpected list functions status 400:")
61+
assert.Empty(t, apitest.ListUnmatchedRequests())
6662
})
6763

6864
t.Run("retries on create failure", func(t *testing.T) {

0 commit comments

Comments
 (0)