From c860a1a70a44ddd0125bda8d43ffbded257ce470 Mon Sep 17 00:00:00 2001 From: mkelvers Date: Wed, 22 Apr 2026 20:39:47 +0200 Subject: [PATCH] fix: validate cache data and suppress static file logging --- Dockerfile | 7 +++++-- entrypoint.sh | 11 +++++++++++ integrations/jikan/client.go | 23 ++++++++++++++++++++--- pkg/middleware/logging.go | 9 +++++++++ 4 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 entrypoint.sh diff --git a/Dockerfile b/Dockerfile index 86e19f1..f50861b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -41,12 +41,15 @@ RUN apt-get update && apt-get install -y ca-certificates sqlite3 && rm -rf /var/ RUN mkdir -p /app/data COPY --from=builder /app/main_server . +COPY --from=builder /app/entrypoint.sh . COPY --from=builder /app/static ./static COPY --from=builder /app/dist ./dist COPY --from=builder /app/migrations ./migrations +RUN chmod +x ./entrypoint.sh + # Expose the application port EXPOSE 3000 -# Run entrypoint which handles migrations -CMD ["./main_server"] +# Run entrypoint which handles migrations and cache clearing +ENTRYPOINT ["./entrypoint.sh"] diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..8fe80ea --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,11 @@ +#!/bin/sh +set -e + +# Clear potentially corrupted Jikan cache entries on each deploy +DB_FILE="${DATABASE_FILE:-/app/data/mal.db}" +if [ -f "$DB_FILE" ]; then + sqlite3 "$DB_FILE" "DELETE FROM jikan_cache WHERE key LIKE 'top:%';" 2>/dev/null || true +fi + +# Start the server +exec ./main_server diff --git a/integrations/jikan/client.go b/integrations/jikan/client.go index 4275865..4256a68 100644 --- a/integrations/jikan/client.go +++ b/integrations/jikan/client.go @@ -232,9 +232,26 @@ type cacheResult struct { hasStale bool } +func isEmptyResult(out any) bool { + switch v := out.(type) { + case *TopAnimeResponse: + return len(v.Data) == 0 + case *SearchResponse: + return len(v.Data) == 0 + case *AnimeResponse: + return v.Data.MalID == 0 + case *EpisodesResponse: + return len(v.Data) == 0 + } + return false +} + func (c *Client) getWithCache(ctx context.Context, cacheKey string, ttl time.Duration, url string, out any) error { if c.getCache(ctx, cacheKey, out) { - return nil + if !isEmptyResult(out) { + return nil + } + log.Printf("jikan: cache hit for %s but data is empty, refetching", cacheKey) } var stale any @@ -245,11 +262,11 @@ func (c *Client) getWithCache(ctx context.Context, cacheKey string, ttl time.Dur staleBytes, marshalErr := json.Marshal(stale) if marshalErr == nil { unmarshalErr := json.Unmarshal(staleBytes, out) - if unmarshalErr == nil { + if unmarshalErr == nil && !isEmptyResult(out) { return nil } } - log.Printf("jikan: stale cache unmarshal failed, falling back to error: %v", err) + log.Printf("jikan: stale cache unmarshal failed or empty, falling back to error: %v", err) } return err } diff --git a/pkg/middleware/logging.go b/pkg/middleware/logging.go index cd766f5..fd73ea4 100644 --- a/pkg/middleware/logging.go +++ b/pkg/middleware/logging.go @@ -6,6 +6,7 @@ import ( "log" "net" "net/http" + "strings" "time" ) @@ -67,6 +68,14 @@ func (rw *statusRecorder) Unwrap() http.ResponseWriter { func RequestLogger(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() + + if strings.HasPrefix(r.URL.Path, "/dist/static/") || + strings.HasPrefix(r.URL.Path, "/static/") || + r.URL.Path == "/favicon.ico" { + next.ServeHTTP(w, r) + return + } + recorder := newStatusRecorder(w) next.ServeHTTP(recorder, r)