require('dotenv').config(); const cron = require('node-cron'); const http = require('http'); const PHP_BASE = process.env.PHP_BASE_URL || 'http://127.0.0.1'; const PHP_WEBROOT = process.env.PHP_WEBROOT || '/mn3wms/app'; const SECRET = process.env.EMIT_SECRET || ''; function callPhp(path, body) { return new Promise((resolve, reject) => { const payload = JSON.stringify(body); const url = new URL(PHP_BASE + PHP_WEBROOT + path); const options = { hostname: url.hostname, port: url.port || 80, path: url.pathname, method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload), 'x-cron-secret': SECRET, }, }; const req = http.request(options, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { try { resolve(JSON.parse(data)); } catch (e) { reject(new Error('Bad JSON: ' + data.slice(0, 100))); } }); }); req.on('error', reject); req.write(payload); req.end(); }); } // ── ETL GL Summary maintenance — runs every hour ───────────────────────────── // Checks and repairs etl_gl_summary (GL aggregation table). // Each company has a fixed slot = company_id % 24 — load is spread across 24 hours. // For etl_stock_summary add a separate schedule below when ready. cron.schedule('0 * * * *', async () => { const slot = new Date().getHours(); console.log(`[scheduler] etl_gl slot=${slot}`); try { const result = await callPhp('/cron/etl_gl_maintenance.php', { slot }); const summary = (result.results || []).map(r => r.error ? `company=${r.company_id} ERROR: ${r.error}` : `company=${r.company_id} gaps=${r.gaps_found} rebuilt=${r.periods_rebuilt}` ); if (summary.length === 0) { console.log(`[scheduler] etl_gl slot=${slot} — no companies`); } else { summary.forEach(s => console.log(`[scheduler] etl_gl ${s}`)); } } catch (e) { console.error('[scheduler] etl_gl_maintenance failed:', e.message); } }); // ── ETL Stock Summary maintenance — runs every hour ────────────────────────── // Checks and repairs etl_stock_summary (stock aggregation table). // Same slot-based distribution as GL: company_id % 24. cron.schedule('30 * * * *', async () => { const slot = new Date().getHours(); console.log(`[scheduler] etl_stock slot=${slot}`); try { const result = await callPhp('/cron/etl_stock_maintenance.php', { slot }); const summary = (result.results || []).map(r => r.error ? `company=${r.company_id} ERROR: ${r.error}` : `company=${r.company_id} gaps=${r.gaps_found} rebuilt=${r.periods_rebuilt}` ); if (summary.length === 0) { console.log(`[scheduler] etl_stock slot=${slot} — no companies`); } else { summary.forEach(s => console.log(`[scheduler] etl_stock ${s}`)); } } catch (e) { console.error('[scheduler] etl_stock_maintenance failed:', e.message); } }); console.log('[scheduler] running — etl_gl_maintenance + etl_stock_maintenance wired (hourly, slot-based)');