@@ -256,6 +256,24 @@ export class FeederService {
|
|||||||
this.logger.log("🎉 HISTORICAL SCAN COMPLETED");
|
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
|
// PROCESS SINGLE DATE
|
||||||
// ============================================
|
// ============================================
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import {
|
|||||||
getShiftedDateStringInTimeZone,
|
getShiftedDateStringInTimeZone,
|
||||||
} from "../common/utils/timezone.util";
|
} from "../common/utils/timezone.util";
|
||||||
import { TaskLockService } from "./task-lock.service";
|
import { TaskLockService } from "./task-lock.service";
|
||||||
|
import { FeederService } from "../modules/feeder/feeder.service";
|
||||||
|
|
||||||
// ────────────────────────────────────────────────────────────────
|
// ────────────────────────────────────────────────────────────────
|
||||||
// Types
|
// Types
|
||||||
@@ -106,6 +107,7 @@ export class DataFetcherTask {
|
|||||||
private readonly prisma: PrismaService,
|
private readonly prisma: PrismaService,
|
||||||
private readonly scraper: FeederScraperService,
|
private readonly scraper: FeederScraperService,
|
||||||
private readonly taskLock: TaskLockService,
|
private readonly taskLock: TaskLockService,
|
||||||
|
private readonly feeder: FeederService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
// ────────────────────────────────────────────────────────────
|
// ────────────────────────────────────────────────────────────
|
||||||
@@ -203,6 +205,7 @@ export class DataFetcherTask {
|
|||||||
await this.syncMatchList(today);
|
await this.syncMatchList(today);
|
||||||
await this.syncMatchList(tomorrow);
|
await this.syncMatchList(tomorrow);
|
||||||
await this.updateLiveScores();
|
await this.updateLiveScores();
|
||||||
|
await this.archiveNewlyFinishedMatches(today);
|
||||||
await this.settlePredictionRuns();
|
await this.settlePredictionRuns();
|
||||||
await this.fetchOddsForMatches();
|
await this.fetchOddsForMatches();
|
||||||
await this.fillMissingLineups();
|
await this.fillMissingLineups();
|
||||||
@@ -210,6 +213,43 @@ export class DataFetcherTask {
|
|||||||
this.logger.log("syncLiveMatches END");
|
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> {
|
private async syncMatchList(date: string): Promise<void> {
|
||||||
// Football
|
// Football
|
||||||
const footballLeagues = this.loadLeagueFilterSet("qualified_leagues.json");
|
const footballLeagues = this.loadLeagueFilterSet("qualified_leagues.json");
|
||||||
@@ -1080,8 +1120,8 @@ export class DataFetcherTask {
|
|||||||
status: storedStatus,
|
status: storedStatus,
|
||||||
scoreHome: sHome,
|
scoreHome: sHome,
|
||||||
scoreAway: sAway,
|
scoreAway: sAway,
|
||||||
htScoreHome: sHtHome,
|
...(sHtHome !== null && { htScoreHome: sHtHome }),
|
||||||
htScoreAway: sHtAway,
|
...(sHtAway !== null && { htScoreAway: sHtAway }),
|
||||||
homeTeamId: homeTeamId,
|
homeTeamId: homeTeamId,
|
||||||
awayTeamId: awayTeamId,
|
awayTeamId: awayTeamId,
|
||||||
updatedAt: new Date(),
|
updatedAt: new Date(),
|
||||||
|
|||||||
Reference in New Issue
Block a user