From 4ec352f1f61052fc96eba12d61bf797a86d41d27 Mon Sep 17 00:00:00 2001 From: yusing Date: Fri, 9 Jan 2026 21:48:35 +0800 Subject: [PATCH] refactor(homepage/icon): check service health before fetching icons and add retry logic The icon fetching logic now checks if the target service is healthy before attempting to fetch icons. If the health monitor reports an unhealthy status, the function returns HTTP 503 Service Unavailable instead of proceeding. Additionally, the icon cache lookup now includes infinite retry logic with a 15-second backoff interval, improving resilience during transient service outages. Previously, failed lookups would not be retried. The `route` interface was extended with a `HealthMonitor()` method to support the health check functionality. --- internal/homepage/icons/fetch/fetch.go | 6 +++++- internal/homepage/icons/fetch/route.go | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/internal/homepage/icons/fetch/fetch.go b/internal/homepage/icons/fetch/fetch.go index ef5b34fa..23fe03e6 100644 --- a/internal/homepage/icons/fetch/fetch.go +++ b/internal/homepage/icons/fetch/fetch.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "io" + "math" "net/http" "net/url" "slices" @@ -163,6 +164,9 @@ func FindIcon(ctx context.Context, r route, uri string, variant icons.Variant) ( } } if r, ok := r.(httpRoute); ok { + if mon := r.HealthMonitor(); mon != nil && !mon.Status().Good() { + return FetchResultWithErrorf(http.StatusServiceUnavailable, "service unavailable") + } // fallback to parse html return findIconSlowCached(context.WithValue(ctx, "route", contextValue{r: r, uri: uri}), r.Key()) } @@ -172,7 +176,7 @@ func FindIcon(ctx context.Context, r route, uri string, variant icons.Variant) ( var findIconSlowCached = cache.NewKeyFunc(func(ctx context.Context, key string) (Result, error) { v := ctx.Value("route").(contextValue) return findIconSlow(ctx, v.r, v.uri, nil) -}).WithMaxEntries(200).Build() // no retries, no ttl +}).WithMaxEntries(200).WithRetriesConstantBackoff(math.MaxInt, 15*time.Second).Build() // infinite retries, 15 seconds interval func findIconSlow(ctx context.Context, r httpRoute, uri string, stack []string) (Result, error) { select { diff --git a/internal/homepage/icons/fetch/route.go b/internal/homepage/icons/fetch/route.go index 246561ea..ccd16b7c 100644 --- a/internal/homepage/icons/fetch/route.go +++ b/internal/homepage/icons/fetch/route.go @@ -4,6 +4,7 @@ import ( "net/http" nettypes "github.com/yusing/godoxy/internal/net/types" + "github.com/yusing/godoxy/internal/types" "github.com/yusing/goutils/pool" ) @@ -12,6 +13,7 @@ type route interface { ProviderName() string References() []string TargetURL() *nettypes.URL + HealthMonitor() types.HealthMonitor } type httpRoute interface {