Use a context to ensure a time-based deadline for update operations.

This commit is contained in:
miyuko
2025-09-17 13:00:45 +01:00
parent cf8abbca28
commit 31131a6360
3 changed files with 18 additions and 26 deletions

View File

@@ -1,6 +1,7 @@
package main
import (
"context"
"fmt"
"io"
@@ -11,10 +12,10 @@ import (
"github.com/go-git/go-git/v6/storage/memory"
)
func FetchRepository(repoURL string, branch string) (*Manifest, error) {
func FetchRepository(ctx context.Context, repoURL string, branch string) (*Manifest, error) {
storer := memory.NewStorage()
repo, err := git.Clone(storer, nil, &git.CloneOptions{
repo, err := git.CloneContext(ctx, storer, nil, &git.CloneOptions{
Bare: true,
URL: repoURL,
ReferenceName: plumbing.ReferenceName(branch),

View File

@@ -2,6 +2,7 @@ package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
@@ -176,7 +177,9 @@ func putPage(w http.ResponseWriter, r *http.Request) error {
branch = "pages"
}
result := UpdateWithTimeout(webRoot, repoURL, branch, updateTimeout)
ctx, cancel := context.WithTimeout(r.Context(), updateTimeout)
defer cancel()
result := Update(ctx, webRoot, repoURL, branch)
if result.manifest != nil {
w.Header().Add("Content-Location", r.URL.String())
}
@@ -285,7 +288,9 @@ func postPage(w http.ResponseWriter, r *http.Request) error {
return fmt.Errorf("invalid clone URL")
}
result := UpdateWithTimeout(webRoot, repoURL, "pages", updateTimeout)
ctx, cancel := context.WithTimeout(r.Context(), updateTimeout)
defer cancel()
result := Update(ctx, webRoot, repoURL, "pages")
switch result.outcome {
case UpdateError:
w.WriteHeader(http.StatusServiceUnavailable)

View File

@@ -1,9 +1,10 @@
package main
import (
"context"
"errors"
"fmt"
"log"
"time"
)
type UpdateOutcome int
@@ -23,6 +24,7 @@ type UpdateResult struct {
}
func Update(
ctx context.Context,
webRoot string,
repoURL string,
branch string,
@@ -33,8 +35,11 @@ func Update(
log.Println("update:", webRoot, repoURL, branch)
outcome := UpdateError
fetchManifest, err = FetchRepository(repoURL, branch)
if err == nil {
fetchManifest, err = FetchRepository(ctx, repoURL, branch)
if errors.Is(err, context.DeadlineExceeded) {
outcome = UpdateTimeout
err = fmt.Errorf("update timeout")
} else if err == nil {
oldManifest, _ = backend.GetManifest(webRoot)
newManifest, err = StoreManifest(backend, webRoot, fetchManifest)
if err == nil {
@@ -65,22 +70,3 @@ func Update(
return UpdateResult{outcome, newManifest, err}
}
func UpdateWithTimeout(
webRoot string,
repoURL string,
branch string,
timeout time.Duration,
) UpdateResult {
c := make(chan UpdateResult, 1)
go func() {
result := Update(webRoot, repoURL, branch)
c <- result
}()
select {
case result := <-c:
return result
case <-time.After(timeout):
return UpdateResult{outcome: UpdateTimeout, err: fmt.Errorf("update timeout")}
}
}