mirror of
https://github.com/R0m1k3/Apiflow-gateway.git
synced 2026-10-17 20:26:46 +02:00
- Schéma Hostinger recopié automatiquement depuis PG Debian (colonnes, PK, index) : plus d'init.sql maintenu à la main (corrige articles.artcentrale, mvtart.no_id et les 12 tables manquantes) - Stratégies : full transactionnel (DELETE + INSERT, garde-fou de volume) et window (signature mensuelle + 10 derniers jours) pour les grosses tables - Attente de la fin de la sync Debian (_run), pg_try_advisory_lock, cron 07:30 Europe/Paris, force honoré, alertes webhook - Dashboard : basic auth, CSP sans script inline, plus d'innerHTML, port 3002 non publié (accès via Nginx Proxy Manager) - Secrets hors du compose (.env), frps épinglé 0.71.0 avec TLS forcé, allowPorts et additionalScopes - Suppression de sync.sh, tables.js, utils.js, init.sql ; README de déploiement L'ancien mot de passe de la base `post` figure dans l'historique git : il doit être changé sur le serveur (voir README). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
60 lines
2.2 KiB
JavaScript
60 lines
2.2 KiB
JavaScript
'use strict';
|
|
/**
|
|
* Point d'entrée du service ff_sync_hostinger.
|
|
*
|
|
* node index.js → dashboard + cron (SYNC_CRON, fuseau SYNC_TZ)
|
|
* node index.js --once → une exécution normale puis sortie
|
|
* node index.js --force → une exécution forcée (garde-fou volume ignoré,
|
|
* tables "fenêtre" rechargées entièrement) puis sortie
|
|
*
|
|
* Le verrou consultatif PostgreSQL empêche toute exécution concurrente,
|
|
* y compris entre le service et une commande `docker exec … node index.js --once`.
|
|
*/
|
|
const cron = require('node-cron');
|
|
const { config } = require('./config');
|
|
const log = require('./logger');
|
|
const { closeAll } = require('./db');
|
|
const { runSync } = require('./sync');
|
|
const { startDashboard, registerSyncFn, registerNextRunFn } = require('./server');
|
|
|
|
const args = process.argv.slice(2);
|
|
const force = args.includes('--force');
|
|
const once = force || args.includes('--once');
|
|
|
|
if (once) {
|
|
runSync({ force, trigger: 'cli' })
|
|
.then(async r => {
|
|
await closeAll();
|
|
process.exit(r.skipped || r.status === 'ok' ? 0 : 1);
|
|
})
|
|
.catch(async err => {
|
|
log.error(`Erreur fatale : ${err.message}`);
|
|
await closeAll();
|
|
process.exit(1);
|
|
});
|
|
} else {
|
|
if (!cron.validate(config.cron)) {
|
|
log.error(`SYNC_CRON invalide : "${config.cron}"`);
|
|
process.exit(1);
|
|
}
|
|
registerSyncFn(runSync);
|
|
const task = cron.schedule(
|
|
config.cron,
|
|
() => runSync({ force: false, trigger: 'cron' }).catch(err => log.error(`Sync cron : ${err.message}`)),
|
|
{ timezone: config.timeZone, name: 'ff-sync', noOverlap: true },
|
|
);
|
|
registerNextRunFn(() => task.getNextRun());
|
|
const server = startDashboard();
|
|
log.info(`Service sync Hostinger démarré — cron "${config.cron}" (${config.timeZone}), prochaine exécution ${task.getNextRun()?.toISOString() ?? '?'}`);
|
|
|
|
const shutdown = sig => {
|
|
log.info(`${sig} reçu — arrêt (une transaction en cours est annulée par PostgreSQL)`);
|
|
task.stop();
|
|
server.close();
|
|
closeAll().finally(() => process.exit(0));
|
|
setTimeout(() => process.exit(0), 5000).unref();
|
|
};
|
|
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
}
|