feat: add Hono backend API server with tiered scheduler
Standalone Node.js backend that owns the SQLite database and serves composed data via REST endpoints. Replaces the shell-scheduled scraper with in-process node-cron tiered scheduling. Backend structure: - Hono HTTP server on port 3001 with CORS and request logging - Singleton SQLite connection with WAL mode - In-memory TTL cache for Queue-Times and fetchToday responses - Comparison check on fetchToday (read-before-write, only upserts on change) API endpoints: - GET /api/calendar/week — week schedule + live ride counts for all parks - GET /api/calendar/:parkId/month — month calendar for one park - GET /api/parks — park list with metadata - GET /api/parks/:id — single park detail - GET /api/parks/:id/rides — live rides with Queue-Times/schedule fallback - GET /api/status — health check, scrape stats - POST /api/scrape/trigger — manual scrape (scope: today/month/upcoming/full) Scheduler tiers: - Tier 1: today — hourly (Mar-Dec) - Tier 2: current month — every 6 hours - Tier 3: upcoming — twice daily (3 AM + 3 PM) - Tier 4: full year — daily at 3 AM Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
import cron from "node-cron";
|
||||
import { scrapeToday, scrapeCurrentMonth, scrapeUpcomingMonths, scrapeFullYear } from "./scraper";
|
||||
|
||||
let initialized = false;
|
||||
|
||||
export function startScheduler(): void {
|
||||
if (initialized) return;
|
||||
initialized = true;
|
||||
|
||||
// Tier 1: Today — every hour during operating season (Mar-Dec)
|
||||
cron.schedule("0 * * 3-12 *", async () => {
|
||||
console.log(`[scheduler] tier-1: scraping today @ ${new Date().toISOString()}`);
|
||||
await scrapeToday().catch((err) => console.error("[scheduler] tier-1 error:", err));
|
||||
});
|
||||
|
||||
// Tier 2: This week — every 6 hours, current month for all parks
|
||||
cron.schedule("0 */6 * * *", async () => {
|
||||
console.log(`[scheduler] tier-2: scraping current month @ ${new Date().toISOString()}`);
|
||||
await scrapeCurrentMonth().catch((err) => console.error("[scheduler] tier-2 error:", err));
|
||||
});
|
||||
|
||||
// Tier 3: Upcoming — twice daily (3 AM, 3 PM), current + next month
|
||||
cron.schedule("0 3,15 * * *", async () => {
|
||||
console.log(`[scheduler] tier-3: scraping upcoming months @ ${new Date().toISOString()}`);
|
||||
await scrapeUpcomingMonths().catch((err) => console.error("[scheduler] tier-3 error:", err));
|
||||
});
|
||||
|
||||
// Tier 4: Full season — once daily at 3 AM
|
||||
cron.schedule("0 3 * * *", async () => {
|
||||
console.log(`[scheduler] tier-4: scraping full year @ ${new Date().toISOString()}`);
|
||||
await scrapeFullYear().catch((err) => console.error("[scheduler] tier-4 error:", err));
|
||||
});
|
||||
|
||||
console.log("[scheduler] cron jobs registered");
|
||||
console.log(" tier-1: today — hourly (Mar-Dec)");
|
||||
console.log(" tier-2: current month — every 6h");
|
||||
console.log(" tier-3: upcoming — 3 AM + 3 PM");
|
||||
console.log(" tier-4: full year — 3 AM daily");
|
||||
}
|
||||
Reference in New Issue
Block a user