Skip to content

Commit 560267c

Browse files
committed
fix(deploy): retry the post-commit deploy fence write
1 parent db034d3 commit 560267c

2 files changed

Lines changed: 49 additions & 1 deletion

File tree

internal/handler/deployfence.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ func (h *Handlers) fenceFinalizedDeploy(ctx context.Context, site sitekey.Slug,
1717
"later upload with the same token can overwrite what is live")
1818
return
1919
}
20-
if err := h.DeployFence.MarkDeployFinalized(ctx, site, deployID, mode, h.DeployJWTTTL); err != nil {
20+
err := retryIdempotentCommit(ctx, func(ctx context.Context) error {
21+
return h.DeployFence.MarkDeployFinalized(ctx, site, deployID, mode, h.DeployJWTTTL)
22+
})
23+
if err != nil {
2124
slog.ErrorContext(ctx, "deploy.fence.failed", "site", site, "deployId", deployID, "mode", mode, "err", err,
2225
"detail", "neither the upload fence nor the mode fence was written, so the permit can still "+
2326
"overwrite this deploy or repoint its alias until it expires")
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package handler
2+
3+
import (
4+
"context"
5+
"errors"
6+
"testing"
7+
"time"
8+
9+
"github.com/stretchr/testify/require"
10+
11+
"github.com/freeCodeCamp/artemis/internal/sitekey"
12+
)
13+
14+
type flakyDeployFence struct {
15+
failures int
16+
attempts int
17+
marked bool
18+
}
19+
20+
func (f *flakyDeployFence) MarkDeployFinalized(context.Context, sitekey.Slug, string, string, time.Duration) error {
21+
f.attempts++
22+
if f.attempts <= f.failures {
23+
return errors.New("dial tcp 10.43.0.1:6379: connect: connection refused")
24+
}
25+
f.marked = true
26+
return nil
27+
}
28+
29+
func (f *flakyDeployFence) IsDeployFinalized(context.Context, sitekey.Slug, string) (bool, error) {
30+
return f.marked, nil
31+
}
32+
33+
func (f *flakyDeployFence) IsDeployModeFinalized(context.Context, sitekey.Slug, string, string) (bool, error) {
34+
return f.marked, nil
35+
}
36+
37+
func TestFenceFinalizedDeployRetriesATransientWriteFailure(t *testing.T) {
38+
fence := &flakyDeployFence{failures: indexCommitAttempts - 1}
39+
h := &Handlers{DeployFence: fence, DeployJWTTTL: time.Minute}
40+
41+
h.fenceFinalizedDeploy(context.Background(), "www", "20260420-141522-abc1234", "preview")
42+
43+
require.True(t, fence.marked, "the fence must be written after a transient failure")
44+
require.Equal(t, indexCommitAttempts, fence.attempts)
45+
}

0 commit comments

Comments
 (0)