@@ -256,6 +256,24 @@ export class FeederService {
|
||||
this.logger.log("🎉 HISTORICAL SCAN COMPLETED");
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// INTRADAY ARCHIVE: finished live matches → matches table
|
||||
// ============================================
|
||||
async archiveCompletedMatchesForDate(
|
||||
dateStr: string,
|
||||
sports: Sport[] = this.SPORTS,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`📦 Archiving completed matches for ${dateStr} [${sports.join(", ")}]`,
|
||||
);
|
||||
for (const sport of sports) {
|
||||
await this.processDate(dateStr, sport, [], {
|
||||
onlyCompletedMatches: true,
|
||||
refreshExistingMatches: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// PROCESS SINGLE DATE
|
||||
// ============================================
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
getShiftedDateStringInTimeZone,
|
||||
} from "../common/utils/timezone.util";
|
||||
import { TaskLockService } from "./task-lock.service";
|
||||
import { FeederService } from "../modules/feeder/feeder.service";
|
||||
|
||||
// ────────────────────────────────────────────────────────────────
|
||||
// Types
|
||||
@@ -106,6 +107,7 @@ export class DataFetcherTask {
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly scraper: FeederScraperService,
|
||||
private readonly taskLock: TaskLockService,
|
||||
private readonly feeder: FeederService,
|
||||
) {}
|
||||
|
||||
// ────────────────────────────────────────────────────────────
|
||||
@@ -203,6 +205,7 @@ export class DataFetcherTask {
|
||||
await this.syncMatchList(today);
|
||||
await this.syncMatchList(tomorrow);
|
||||
await this.updateLiveScores();
|
||||
await this.archiveNewlyFinishedMatches(today);
|
||||
await this.settlePredictionRuns();
|
||||
await this.fetchOddsForMatches();
|
||||
await this.fillMissingLineups();
|
||||
@@ -210,6 +213,43 @@ export class DataFetcherTask {
|
||||
this.logger.log("syncLiveMatches END");
|
||||
}
|
||||
|
||||
private async archiveNewlyFinishedMatches(todayStr: string): Promise<void> {
|
||||
try {
|
||||
const finishedLive = await this.prisma.liveMatch.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
{ status: { in: FINISHED_STATUS_VALUES_FOR_DB } },
|
||||
{ state: { in: FINISHED_STATE_VALUES_FOR_DB } },
|
||||
],
|
||||
scoreHome: { not: null },
|
||||
scoreAway: { not: null },
|
||||
},
|
||||
select: { id: true },
|
||||
});
|
||||
|
||||
if (finishedLive.length === 0) return;
|
||||
|
||||
const ids = finishedLive.map((m) => m.id);
|
||||
const alreadyArchived = await this.prisma.match.findMany({
|
||||
where: { id: { in: ids } },
|
||||
select: { id: true },
|
||||
});
|
||||
|
||||
const archivedSet = new Set(alreadyArchived.map((m) => m.id));
|
||||
const newCount = ids.filter((id) => !archivedSet.has(id)).length;
|
||||
|
||||
if (newCount === 0) return;
|
||||
|
||||
this.logger.log(
|
||||
`${newCount} finished match(es) not yet archived — running feeder for ${todayStr}`,
|
||||
);
|
||||
await this.feeder.archiveCompletedMatchesForDate(todayStr);
|
||||
} catch (error: unknown) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
this.logger.error(`archiveNewlyFinishedMatches failed: ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
private async syncMatchList(date: string): Promise<void> {
|
||||
// Football
|
||||
const footballLeagues = this.loadLeagueFilterSet("qualified_leagues.json");
|
||||
@@ -1080,8 +1120,8 @@ export class DataFetcherTask {
|
||||
status: storedStatus,
|
||||
scoreHome: sHome,
|
||||
scoreAway: sAway,
|
||||
htScoreHome: sHtHome,
|
||||
htScoreAway: sHtAway,
|
||||
...(sHtHome !== null && { htScoreHome: sHtHome }),
|
||||
...(sHtAway !== null && { htScoreAway: sHtAway }),
|
||||
homeTeamId: homeTeamId,
|
||||
awayTeamId: awayTeamId,
|
||||
updatedAt: new Date(),
|
||||
|
||||
Reference in New Issue
Block a user