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.
This commit is contained in:
yusing
2026-01-09 21:48:35 +08:00
parent df530245bd
commit 4ec352f1f6
2 changed files with 7 additions and 1 deletions

View File

@@ -6,6 +6,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"math"
"net/http" "net/http"
"net/url" "net/url"
"slices" "slices"
@@ -163,6 +164,9 @@ func FindIcon(ctx context.Context, r route, uri string, variant icons.Variant) (
} }
} }
if r, ok := r.(httpRoute); ok { 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 // fallback to parse html
return findIconSlowCached(context.WithValue(ctx, "route", contextValue{r: r, uri: uri}), r.Key()) 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) { var findIconSlowCached = cache.NewKeyFunc(func(ctx context.Context, key string) (Result, error) {
v := ctx.Value("route").(contextValue) v := ctx.Value("route").(contextValue)
return findIconSlow(ctx, v.r, v.uri, nil) 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) { func findIconSlow(ctx context.Context, r httpRoute, uri string, stack []string) (Result, error) {
select { select {

View File

@@ -4,6 +4,7 @@ import (
"net/http" "net/http"
nettypes "github.com/yusing/godoxy/internal/net/types" nettypes "github.com/yusing/godoxy/internal/net/types"
"github.com/yusing/godoxy/internal/types"
"github.com/yusing/goutils/pool" "github.com/yusing/goutils/pool"
) )
@@ -12,6 +13,7 @@ type route interface {
ProviderName() string ProviderName() string
References() []string References() []string
TargetURL() *nettypes.URL TargetURL() *nettypes.URL
HealthMonitor() types.HealthMonitor
} }
type httpRoute interface { type httpRoute interface {