gl aggregate table (ETL), cronjob by NODEJS

This commit is contained in:
Thanakorn S
2026-05-23 10:52:27 +07:00
parent 5a3bfa3435
commit 5780183b82
15 changed files with 1048 additions and 230 deletions
+5
View File
@@ -5,5 +5,10 @@
PORT=3000
# Secret key — PHP sends this in x-emit-secret header to authenticate /emit calls
# Also used by Node.js scheduler as x-cron-secret when calling PHP cron endpoints
# Use a long random string in production
EMIT_SECRET=
# PHP internal base URL (scheduler → PHP cron endpoints)
PHP_BASE_URL=http://127.0.0.1
PHP_WEBROOT=/mn3wms/app
+10
View File
@@ -10,6 +10,7 @@
"dependencies": {
"dotenv": "^16.0.0",
"express": "^4.18.0",
"node-cron": "^4.2.1",
"socket.io": "^4.7.0"
}
},
@@ -651,6 +652,15 @@
"node": ">= 0.6"
}
},
"node_modules/node-cron": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/node-cron/-/node-cron-4.2.1.tgz",
"integrity": "sha512-lgimEHPE/QDgFlywTd8yTR61ptugX3Qer29efeyWw2rv259HtGBNn1vZVmp8lB9uo9wC0t/AT4iGqXxia+CJFg==",
"license": "ISC",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+3 -2
View File
@@ -7,8 +7,9 @@
"start": "node server.js"
},
"dependencies": {
"dotenv": "^16.0.0",
"express": "^4.18.0",
"socket.io": "^4.7.0",
"dotenv": "^16.0.0"
"node-cron": "^4.2.1",
"socket.io": "^4.7.0"
}
}
+67
View File
@@ -0,0 +1,67 @@
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);
}
});
console.log('[scheduler] running — etl_gl_maintenance wired (hourly, slot-based)');