The job_run_logs table tracks scheduled job orchestration, not individual worker jobs. Worker info (worker_id, worker_hostname) belongs on dispensary_crawl_jobs, not job_run_logs. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
105 lines
4.0 KiB
JavaScript
105 lines
4.0 KiB
JavaScript
"use strict";
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.startScheduler = startScheduler;
|
|
exports.stopScheduler = stopScheduler;
|
|
exports.restartScheduler = restartScheduler;
|
|
exports.triggerStoreScrape = triggerStoreScrape;
|
|
exports.triggerAllStoresScrape = triggerAllStoresScrape;
|
|
const node_cron_1 = __importDefault(require("node-cron"));
|
|
const migrate_1 = require("../db/migrate");
|
|
const scraper_v2_1 = require("../scraper-v2");
|
|
let scheduledJobs = [];
|
|
async function getSettings() {
|
|
const result = await migrate_1.pool.query(`
|
|
SELECT key, value FROM settings
|
|
WHERE key IN ('scrape_interval_hours', 'scrape_specials_time')
|
|
`);
|
|
const settings = {};
|
|
result.rows.forEach((row) => {
|
|
settings[row.key] = row.value;
|
|
});
|
|
return {
|
|
scrapeIntervalHours: parseInt(settings.scrape_interval_hours || '4'),
|
|
scrapeSpecialsTime: settings.scrape_specials_time || '00:01'
|
|
};
|
|
}
|
|
async function scrapeAllStores() {
|
|
console.log('🔄 Starting scheduled scrape for all stores...');
|
|
const result = await migrate_1.pool.query(`
|
|
SELECT id, name FROM stores WHERE active = true AND scrape_enabled = true
|
|
`);
|
|
for (const store of result.rows) {
|
|
try {
|
|
console.log(`Scraping store: ${store.name}`);
|
|
await (0, scraper_v2_1.scrapeStore)(store.id);
|
|
}
|
|
catch (error) {
|
|
console.error(`Failed to scrape store ${store.name}:`, error);
|
|
}
|
|
}
|
|
console.log('✅ Scheduled scrape completed');
|
|
}
|
|
async function scrapeSpecials() {
|
|
console.log('🌟 Starting scheduled specials scrape...');
|
|
const result = await migrate_1.pool.query(`
|
|
SELECT s.id, s.name, c.id as category_id
|
|
FROM stores s
|
|
JOIN categories c ON c.store_id = s.id
|
|
WHERE s.active = true AND s.scrape_enabled = true
|
|
AND c.slug = 'specials' AND c.scrape_enabled = true
|
|
`);
|
|
for (const row of result.rows) {
|
|
try {
|
|
console.log(`Scraping specials for: ${row.name}`);
|
|
await (0, scraper_v2_1.scrapeCategory)(row.id, row.category_id);
|
|
}
|
|
catch (error) {
|
|
console.error(`Failed to scrape specials for ${row.name}:`, error);
|
|
}
|
|
}
|
|
console.log('✅ Specials scrape completed');
|
|
}
|
|
async function startScheduler() {
|
|
// Stop any existing jobs
|
|
stopScheduler();
|
|
const settings = await getSettings();
|
|
// Schedule regular store scrapes (every N hours)
|
|
const scrapeIntervalCron = `0 */${settings.scrapeIntervalHours} * * *`;
|
|
const storeJob = node_cron_1.default.schedule(scrapeIntervalCron, scrapeAllStores);
|
|
scheduledJobs.push(storeJob);
|
|
console.log(`📅 Scheduled store scraping: every ${settings.scrapeIntervalHours} hours`);
|
|
// Schedule specials scraping (daily at specified time)
|
|
const [hours, minutes] = settings.scrapeSpecialsTime.split(':');
|
|
const specialsCron = `${minutes} ${hours} * * *`;
|
|
const specialsJob = node_cron_1.default.schedule(specialsCron, scrapeSpecials);
|
|
scheduledJobs.push(specialsJob);
|
|
console.log(`📅 Scheduled specials scraping: daily at ${settings.scrapeSpecialsTime}`);
|
|
// Initial scrape on startup (after 10 seconds)
|
|
setTimeout(() => {
|
|
console.log('🚀 Running initial scrape...');
|
|
scrapeAllStores().catch(console.error);
|
|
}, 10000);
|
|
}
|
|
function stopScheduler() {
|
|
scheduledJobs.forEach(job => job.stop());
|
|
scheduledJobs = [];
|
|
console.log('🛑 Scheduler stopped');
|
|
}
|
|
async function restartScheduler() {
|
|
console.log('🔄 Restarting scheduler...');
|
|
stopScheduler();
|
|
await startScheduler();
|
|
}
|
|
// Manual trigger functions for admin
|
|
async function triggerStoreScrape(storeId) {
|
|
console.log(`🔧 Manual scrape triggered for store ID: ${storeId}`);
|
|
await (0, scraper_v2_1.scrapeStore)(storeId);
|
|
}
|
|
async function triggerAllStoresScrape() {
|
|
console.log('🔧 Manual scrape triggered for all stores');
|
|
await scrapeAllStores();
|
|
}
|