feat: bump availability version to 4 and drop jikan-only cache paths
This commit is contained in:
@@ -4,32 +4,28 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"mal/integrations/jikan"
|
|
||||||
"mal/internal/db"
|
"mal/internal/db"
|
||||||
"mal/internal/domain"
|
"mal/internal/domain"
|
||||||
"mal/internal/observability"
|
"mal/internal/observability"
|
||||||
)
|
)
|
||||||
|
|
||||||
const episodeAvailabilityPayloadVersion = 2
|
const episodeAvailabilityPayloadVersion = 4
|
||||||
|
|
||||||
func (s *EpisodeService) store(ctx context.Context, anime domain.Anime, jikanEpisodes []jikan.Episode, availability domain.EpisodeAvailability, source string, now time.Time, providerSuccess bool) (domain.CanonicalEpisodeList, error) {
|
func (s *EpisodeService) store(ctx context.Context, anime domain.Anime, availability domain.EpisodeAvailability, source string, now time.Time) (domain.CanonicalEpisodeList, error) {
|
||||||
nextRefreshSQL := nextRefreshAt(anime, now)
|
nextRefreshSQL := nextRefreshAt(anime, now)
|
||||||
episodes := mergeEpisodesForAnime(anime, jikanEpisodes, availability, now, providerSuccess)
|
episodes := mergeEpisodes(nil, availability, 0)
|
||||||
payload := domain.CanonicalEpisodeList{
|
payload := domain.CanonicalEpisodeList{
|
||||||
AnimeID: anime.MalID,
|
AnimeID: anime.MalID,
|
||||||
Episodes: episodes,
|
Episodes: episodes,
|
||||||
Source: source,
|
Source: source,
|
||||||
AvailabilityVersion: episodeAvailabilityPayloadVersion,
|
AvailabilityVersion: episodeAvailabilityPayloadVersion,
|
||||||
ReleaseChecked: !providerSuccess,
|
ReleaseChecked: false,
|
||||||
LastAttemptAt: now.Format(time.RFC3339),
|
LastAttemptAt: now.Format(time.RFC3339),
|
||||||
FailureCount: 0,
|
FailureCount: 0,
|
||||||
}
|
}
|
||||||
if providerSuccess {
|
payload.LastSuccessAt = now.Format(time.RFC3339)
|
||||||
payload.LastSuccessAt = now.Format(time.RFC3339)
|
|
||||||
}
|
|
||||||
if nextRefreshSQL.Valid {
|
if nextRefreshSQL.Valid {
|
||||||
payload.NextRefreshAt = nextRefreshSQL.Time.Format(time.RFC3339)
|
payload.NextRefreshAt = nextRefreshSQL.Time.Format(time.RFC3339)
|
||||||
}
|
}
|
||||||
@@ -39,7 +35,7 @@ func (s *EpisodeService) store(ctx context.Context, anime domain.Anime, jikanEpi
|
|||||||
return domain.CanonicalEpisodeList{}, err
|
return domain.CanonicalEpisodeList{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !s.writeEpisodeAvailabilityCache(ctx, anime, source, body, now, providerSuccess, nextRefreshSQL) {
|
if !s.writeEpisodeAvailabilityCache(ctx, anime, source, body, now, true, nextRefreshSQL) {
|
||||||
return payload, nil
|
return payload, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,8 +238,11 @@ func (s *EpisodeService) decodeCachedPayload(anime domain.Anime, raw string) (do
|
|||||||
)
|
)
|
||||||
return domain.CanonicalEpisodeList{}, false
|
return domain.CanonicalEpisodeList{}, false
|
||||||
}
|
}
|
||||||
|
if payload.Source == "jikan_fallback" || payload.Source == "legacy_disabled" {
|
||||||
|
return domain.CanonicalEpisodeList{}, false
|
||||||
|
}
|
||||||
|
|
||||||
if isStaleAiringEpisodePayload(anime, payload) {
|
if isStaleProviderEpisodePayload(payload) {
|
||||||
observability.Info(
|
observability.Info(
|
||||||
"episodes_cached_payload_rejected_stale_version",
|
"episodes_cached_payload_rejected_stale_version",
|
||||||
"episodes",
|
"episodes",
|
||||||
@@ -258,20 +257,6 @@ func (s *EpisodeService) decodeCachedPayload(anime domain.Anime, raw string) (do
|
|||||||
return domain.CanonicalEpisodeList{}, false
|
return domain.CanonicalEpisodeList{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
if isUncheckedAiringJikanFallback(anime, payload) {
|
|
||||||
observability.Info(
|
|
||||||
"episodes_cached_payload_rejected_unchecked_fallback",
|
|
||||||
"episodes",
|
|
||||||
"",
|
|
||||||
map[string]any{
|
|
||||||
"anime_id": anime.MalID,
|
|
||||||
"cached_episodes": len(payload.Episodes),
|
|
||||||
"source": payload.Source,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
return domain.CanonicalEpisodeList{}, false
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isCanonicalEpisodePayloadValid(payload, anime.Episodes) {
|
if !isCanonicalEpisodePayloadValid(payload, anime.Episodes) {
|
||||||
observability.Info(
|
observability.Info(
|
||||||
"episodes_cached_payload_rejected",
|
"episodes_cached_payload_rejected",
|
||||||
@@ -289,17 +274,6 @@ func (s *EpisodeService) decodeCachedPayload(anime domain.Anime, raw string) (do
|
|||||||
return payload, true
|
return payload, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func isStaleAiringEpisodePayload(anime domain.Anime, payload domain.CanonicalEpisodeList) bool {
|
func isStaleProviderEpisodePayload(payload domain.CanonicalEpisodeList) bool {
|
||||||
return isAiring(anime) && len(payload.Episodes) > 0 && payload.AvailabilityVersion < episodeAvailabilityPayloadVersion
|
return payload.Source != "" && payload.Source != "jikan_fallback" && payload.Source != "legacy_disabled" && payload.AvailabilityVersion < episodeAvailabilityPayloadVersion
|
||||||
}
|
|
||||||
|
|
||||||
func isUncheckedAiringJikanFallback(anime domain.Anime, payload domain.CanonicalEpisodeList) bool {
|
|
||||||
if !isAiring(anime) || payload.ReleaseChecked || len(payload.Episodes) == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return payload.Source == "jikan_fallback" || payload.Source == "legacy_disabled"
|
|
||||||
}
|
|
||||||
|
|
||||||
func isAiring(anime domain.Anime) bool {
|
|
||||||
return anime.Airing || strings.EqualFold(strings.TrimSpace(anime.Status), "Currently Airing")
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user