fix: validate cache data and suppress static file logging

This commit is contained in:
2026-04-22 20:39:47 +02:00
parent bfb50aa76e
commit c860a1a70a
4 changed files with 45 additions and 5 deletions

View File

@@ -41,12 +41,15 @@ RUN apt-get update && apt-get install -y ca-certificates sqlite3 && rm -rf /var/
RUN mkdir -p /app/data RUN mkdir -p /app/data
COPY --from=builder /app/main_server . COPY --from=builder /app/main_server .
COPY --from=builder /app/entrypoint.sh .
COPY --from=builder /app/static ./static COPY --from=builder /app/static ./static
COPY --from=builder /app/dist ./dist COPY --from=builder /app/dist ./dist
COPY --from=builder /app/migrations ./migrations COPY --from=builder /app/migrations ./migrations
RUN chmod +x ./entrypoint.sh
# Expose the application port # Expose the application port
EXPOSE 3000 EXPOSE 3000
# Run entrypoint which handles migrations # Run entrypoint which handles migrations and cache clearing
CMD ["./main_server"] ENTRYPOINT ["./entrypoint.sh"]

11
entrypoint.sh Normal file
View File

@@ -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

View File

@@ -232,10 +232,27 @@ type cacheResult struct {
hasStale bool 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 { func (c *Client) getWithCache(ctx context.Context, cacheKey string, ttl time.Duration, url string, out any) error {
if c.getCache(ctx, cacheKey, out) { if c.getCache(ctx, cacheKey, out) {
if !isEmptyResult(out) {
return nil return nil
} }
log.Printf("jikan: cache hit for %s but data is empty, refetching", cacheKey)
}
var stale any var stale any
hasStale := c.getStaleCache(ctx, cacheKey, &stale) hasStale := c.getStaleCache(ctx, cacheKey, &stale)
@@ -245,11 +262,11 @@ func (c *Client) getWithCache(ctx context.Context, cacheKey string, ttl time.Dur
staleBytes, marshalErr := json.Marshal(stale) staleBytes, marshalErr := json.Marshal(stale)
if marshalErr == nil { if marshalErr == nil {
unmarshalErr := json.Unmarshal(staleBytes, out) unmarshalErr := json.Unmarshal(staleBytes, out)
if unmarshalErr == nil { if unmarshalErr == nil && !isEmptyResult(out) {
return nil 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 return err
} }

View File

@@ -6,6 +6,7 @@ import (
"log" "log"
"net" "net"
"net/http" "net/http"
"strings"
"time" "time"
) )
@@ -67,6 +68,14 @@ func (rw *statusRecorder) Unwrap() http.ResponseWriter {
func RequestLogger(next http.Handler) http.Handler { func RequestLogger(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now() 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) recorder := newStatusRecorder(w)
next.ServeHTTP(recorder, r) next.ServeHTTP(recorder, r)