This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Repair Feeder - Fix incomplete matches
|
||||
* Usage: npm run feeder:repair
|
||||
*
|
||||
* Finds matches in DB that are missing stats or lineups
|
||||
* and re-fetches them from the API.
|
||||
*/
|
||||
|
||||
import { NestFactory } from "@nestjs/core";
|
||||
import { Logger } from "@nestjs/common";
|
||||
import { PrismaService } from "../database/prisma.service";
|
||||
import { FeederService } from "../modules/feeder/feeder.service";
|
||||
|
||||
async function bootstrap() {
|
||||
process.env.FEEDER_MODE = "historical";
|
||||
|
||||
const logger = new Logger("FeederRepair");
|
||||
|
||||
logger.log("🔧 Starting feeder repair scan...");
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const { AppModule } = require("../app.module");
|
||||
const app = await NestFactory.createApplicationContext(AppModule, {
|
||||
logger: ["log", "error", "warn"],
|
||||
});
|
||||
|
||||
const prisma = app.get(PrismaService);
|
||||
const feederService = app.get(FeederService);
|
||||
|
||||
try {
|
||||
// Find football matches missing stats (no football_team_stats rows)
|
||||
const matchesMissingStats = await prisma.$queryRaw<
|
||||
Array<{ id: string; match_name: string }>
|
||||
>`
|
||||
SELECT m.id, m.match_name
|
||||
FROM matches m
|
||||
LEFT JOIN football_team_stats fts ON fts.match_id = m.id
|
||||
WHERE m.sport = 'football'
|
||||
AND m.state = 'Ended'
|
||||
AND fts.id IS NULL
|
||||
ORDER BY m.mst_utc DESC
|
||||
`;
|
||||
|
||||
// Find football matches missing lineups (< 18 participation rows)
|
||||
const matchesMissingLineups = await prisma.$queryRaw<
|
||||
Array<{ id: string; match_name: string; cnt: bigint }>
|
||||
>`
|
||||
SELECT m.id, m.match_name, COUNT(mpp.id) as cnt
|
||||
FROM matches m
|
||||
LEFT JOIN match_player_participation mpp ON mpp.match_id = m.id
|
||||
WHERE m.sport = 'football'
|
||||
AND m.state = 'Ended'
|
||||
GROUP BY m.id, m.match_name
|
||||
HAVING COUNT(mpp.id) < 18
|
||||
ORDER BY m.mst_utc DESC
|
||||
`;
|
||||
|
||||
// Combine unique match IDs
|
||||
const repairSet = new Set<string>();
|
||||
for (const m of matchesMissingStats) repairSet.add(m.id);
|
||||
for (const m of matchesMissingLineups) repairSet.add(m.id);
|
||||
|
||||
logger.log(
|
||||
`📊 Found ${repairSet.size} incomplete matches (${matchesMissingStats.length} missing stats, ${matchesMissingLineups.length} missing lineups)`,
|
||||
);
|
||||
|
||||
if (repairSet.size === 0) {
|
||||
logger.log("✅ No incomplete matches found. Everything is clean!");
|
||||
await app.close();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
let repaired = 0;
|
||||
let failed = 0;
|
||||
const matchIds = Array.from(repairSet);
|
||||
|
||||
for (let i = 0; i < matchIds.length; i++) {
|
||||
const matchId = matchIds[i];
|
||||
|
||||
// Rate limiting
|
||||
if (i > 0 && i % 10 === 0) {
|
||||
logger.log(
|
||||
`⏸️ Cooldown after 10 repairs... (${repaired} repaired, ${failed} failed, ${matchIds.length - i} remaining)`,
|
||||
);
|
||||
await new Promise((r) => setTimeout(r, 5000));
|
||||
}
|
||||
|
||||
await new Promise((r) => setTimeout(r, 500));
|
||||
|
||||
try {
|
||||
const result = await feederService.refreshMatch(matchId, "all");
|
||||
if (result.success) {
|
||||
repaired++;
|
||||
if (repaired % 25 === 0) {
|
||||
logger.log(`🔧 Progress: ${repaired}/${matchIds.length} repaired`);
|
||||
}
|
||||
} else {
|
||||
failed++;
|
||||
logger.warn(
|
||||
`❌ [${matchId}] Repair failed: ${result.error || "unknown"}`,
|
||||
);
|
||||
}
|
||||
} catch (e: any) {
|
||||
failed++;
|
||||
logger.error(`❌ [${matchId}] Repair exception: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
logger.log(
|
||||
`🎉 REPAIR COMPLETE: ${repaired} repaired, ${failed} failed out of ${matchIds.length} total`,
|
||||
);
|
||||
} catch (error: any) {
|
||||
logger.error(`❌ Repair failed: ${error.message}`);
|
||||
logger.error(error.stack);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
await app.close();
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
void bootstrap();
|
||||
Reference in New Issue
Block a user