Fix three code review findings from Phase A cron jobs
- Remove `| cat` from both Forgejo workflow curl commands so HTTP 4xx/5xx causes the step to fail (bash pipeline exit code was always 0 via cat) - Simplify sync-and-simulate: drop redundant pre-check DB query for standingsLastChangedAt; changed===true already means standings updated this run, so always simulate (runner's simulationStatus guard handles overlap) - Delete server/snapshots.ts — all exports were orphaned after startSnapshotSystem was removed from server/socket.ts in the Phase A commit Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
bfe2350f45
commit
52eb3abac1
4 changed files with 4 additions and 125 deletions
|
|
@ -11,5 +11,4 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
curl -sf -X POST https://brackt.com/admin/jobs/run-daily-snapshots \
|
curl -sf -X POST https://brackt.com/admin/jobs/run-daily-snapshots \
|
||||||
-H "X-Cron-Secret: ${{ secrets.CRON_SECRET }}" \
|
-H "X-Cron-Secret: ${{ secrets.CRON_SECRET }}" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json"
|
||||||
| cat
|
|
||||||
|
|
|
||||||
|
|
@ -11,5 +11,4 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
curl -sf -X POST https://brackt.com/admin/jobs/sync-and-simulate \
|
curl -sf -X POST https://brackt.com/admin/jobs/sync-and-simulate \
|
||||||
-H "X-Cron-Secret: ${{ secrets.CRON_SECRET }}" \
|
-H "X-Cron-Secret: ${{ secrets.CRON_SECRET }}" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json"
|
||||||
| cat
|
|
||||||
|
|
|
||||||
|
|
@ -35,19 +35,8 @@ export async function action({ request }: { request: Request }) {
|
||||||
|
|
||||||
if (!changed) continue;
|
if (!changed) continue;
|
||||||
|
|
||||||
// Only simulate if standings changed since last simulation
|
// changed === true means syncStandings() detected new data this run, so simulate.
|
||||||
const current = await database()
|
// Overlap is guarded inside runSportsSeasonSimulation (throws if simulationStatus === "running").
|
||||||
.select({ standingsLastChangedAt: schema.sportsSeasons.standingsLastChangedAt, lastSimulatedAt: schema.sportsSeasons.lastSimulatedAt })
|
|
||||||
.from(schema.sportsSeasons)
|
|
||||||
.where(eq(schema.sportsSeasons.id, season.id))
|
|
||||||
.then((rows) => rows[0]);
|
|
||||||
|
|
||||||
const needsSim =
|
|
||||||
current?.standingsLastChangedAt &&
|
|
||||||
(!current.lastSimulatedAt || current.standingsLastChangedAt > current.lastSimulatedAt);
|
|
||||||
|
|
||||||
if (!needsSim) continue;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await runSportsSeasonSimulation(season.id);
|
await runSportsSeasonSimulation(season.id);
|
||||||
await database()
|
await database()
|
||||||
|
|
|
||||||
|
|
@ -1,108 +0,0 @@
|
||||||
import * as schema from "~/database/schema";
|
|
||||||
import { eq, or } from "drizzle-orm";
|
|
||||||
import { createDailySnapshot } from "~/models/standings";
|
|
||||||
import { logger } from "./logger";
|
|
||||||
import { db } from "./db";
|
|
||||||
|
|
||||||
let snapshotInterval: NodeJS.Timeout | null = null;
|
|
||||||
const CHECK_INTERVAL = 24 * 60 * 60 * 1000; // Check once per day (in milliseconds)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start the daily snapshot system
|
|
||||||
* Runs once per day to create snapshots for all active seasons
|
|
||||||
*/
|
|
||||||
export function startSnapshotSystem(): void {
|
|
||||||
if (snapshotInterval) {
|
|
||||||
logger.log("[Snapshots] Snapshot system already running");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run immediately on startup
|
|
||||||
void createDailySnapshots();
|
|
||||||
|
|
||||||
// Then run once per day
|
|
||||||
snapshotInterval = setInterval(async () => {
|
|
||||||
try {
|
|
||||||
await createDailySnapshots();
|
|
||||||
} catch (error) {
|
|
||||||
logger.error("[Snapshots] Error creating daily snapshots:", error);
|
|
||||||
}
|
|
||||||
}, CHECK_INTERVAL);
|
|
||||||
|
|
||||||
logger.log("[Snapshots] Daily snapshot system started (runs once per day)");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop the snapshot system
|
|
||||||
*/
|
|
||||||
export function stopSnapshotSystem(): void {
|
|
||||||
if (snapshotInterval) {
|
|
||||||
clearInterval(snapshotInterval);
|
|
||||||
snapshotInterval = null;
|
|
||||||
logger.log("[Snapshots] Snapshot system stopped");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create daily snapshots for all active seasons
|
|
||||||
* Only creates snapshots if they don't already exist for today
|
|
||||||
*/
|
|
||||||
async function createDailySnapshots(): Promise<void> {
|
|
||||||
const now = new Date();
|
|
||||||
const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
|
|
||||||
|
|
||||||
logger.log(`[Snapshots] Checking for snapshots to create (${today})`);
|
|
||||||
|
|
||||||
// Get all seasons that are active or in draft (we want to track standings for these)
|
|
||||||
const activeSeasons = await db.query.seasons.findMany({
|
|
||||||
where: or(
|
|
||||||
eq(schema.seasons.status, "active"),
|
|
||||||
eq(schema.seasons.status, "draft")
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (activeSeasons.length === 0) {
|
|
||||||
logger.log("[Snapshots] No active seasons found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.log(`[Snapshots] Found ${activeSeasons.length} active season(s)`);
|
|
||||||
|
|
||||||
for (const season of activeSeasons) {
|
|
||||||
try {
|
|
||||||
await createDailySnapshot(season.id, db);
|
|
||||||
logger.log(`[Snapshots] ✅ Upserted snapshot for season ${season.id}`);
|
|
||||||
} catch (error) {
|
|
||||||
logger.error(`[Snapshots] Error creating snapshot for season ${season.id}:`, error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.log("[Snapshots] Daily snapshot check complete");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manually trigger snapshot creation for specific seasons
|
|
||||||
* Useful for admin tools or manual triggers
|
|
||||||
*/
|
|
||||||
export async function createSnapshotsForSeasons(seasonIds: string[]): Promise<void> {
|
|
||||||
logger.log(`[Snapshots] Manual trigger for ${seasonIds.length} season(s)`);
|
|
||||||
|
|
||||||
for (const seasonId of seasonIds) {
|
|
||||||
try {
|
|
||||||
await createDailySnapshot(seasonId, db);
|
|
||||||
logger.log(`[Snapshots] ✅ Created snapshot for season ${seasonId}`);
|
|
||||||
} catch (error) {
|
|
||||||
logger.error(`[Snapshots] Error creating snapshot for season ${seasonId}:`, error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manually trigger snapshot creation for all active seasons
|
|
||||||
* Useful for testing or manual refreshes
|
|
||||||
*/
|
|
||||||
export async function createSnapshotsForAllSeasons(): Promise<void> {
|
|
||||||
logger.log("[Snapshots] Manual trigger for all active seasons");
|
|
||||||
await createDailySnapshots();
|
|
||||||
}
|
|
||||||
Loading…
Add table
Reference in a new issue