Skip to content

Commit 2ea9148

Browse files
committed
chore: Fix possible EPG generate and cache race condition
Make sure only valid data is ever used to generate EPG XML files
1 parent 3071485 commit 2ea9148

File tree

4 files changed

+18
-6
lines changed

4 files changed

+18
-6
lines changed

app/Http/Controllers/EpgGenerateController.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -227,11 +227,10 @@ private function generate($playlist)
227227
}
228228

229229
try {
230-
// Try to use cached data first
231-
// if ($cacheService->isCacheValid($epg)) {
232-
// Do a quick check instead of fetching metadata and parsing
233-
// If flagged as cached, use the cache
234-
if ($epg->is_cached) {
230+
// Try to use cached data first with proper validation
231+
// CRITICAL: Check both is_cached flag AND that cache is actually valid
232+
// This prevents race condition where cache is being regenerated
233+
if ($epg->is_cached && $cacheService->isCacheValid($epg)) {
235234
// Get all programmes from cache
236235
$startDate = Carbon::now()->subDays(1)->format('Y-m-d');
237236
$epgDays = config('dev.default_epg_days', 7);

app/Jobs/GenerateEpgCache.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ public function handle(EpgCacheService $cacheService): void
6464
'processing_phase' => null,
6565
]);
6666

67-
// Clear out any related EPG file caches
67+
// Clear playlist EPG cache files AFTER new cache is generated
68+
// This ensures users can still get cached EPG files during regeneration
6869
foreach ($epg->getAllPlaylists() as $playlist) {
6970
EpgCacheService::clearPlaylistEpgCacheFile($playlist);
7071
}

app/Listeners/SyncListener.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,15 @@ private function handleAutoMergeChannels(\App\Models\Playlist $playlist): void
110110
private function postProcessEpg(Epg $epg)
111111
{
112112
// Update status to Processing (so UI components will continue to refresh) and dispatch cache job
113+
// IMPORTANT: Set is_cached to false to prevent race condition where users
114+
// try to read the EPG cache (JSON files) while it's being regenerated
115+
// Note: Playlist EPG cache files (XML) are NOT cleared here - they remain available
116+
// for users until the new cache is generated, preventing fallback to slow XML reader
113117
// Note: processing_started_at and processing_phase will be set by GenerateEpgCache job
114118
$epg->update([
115119
'status' => Status::Processing,
120+
'is_cached' => false,
121+
'cache_meta' => null,
116122
'processing_started_at' => null,
117123
'processing_phase' => null,
118124
]);

app/Services/EpgCacheService.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ private function getCacheFilePath(Epg $epg, string $filename): string
5555
*/
5656
public function isCacheValid(Epg $epg): bool
5757
{
58+
// CRITICAL: If EPG is currently being processed, cache is NOT valid
59+
// This prevents race condition where we try to read a cache being regenerated
60+
if ($epg->processing_phase === 'cache' || $epg->status === Status::Processing) {
61+
return false;
62+
}
63+
5864
$metadataPath = $this->getCacheFilePath($epg, self::METADATA_FILE);
5965

6066
if (!Storage::disk('local')->exists($metadataPath)) {

0 commit comments

Comments
 (0)