// n8n Code node — Health Check // Usa https de Node.js (NODE_FUNCTION_ALLOW_BUILTIN=https) // Patrón async IIFE: compatible con n8n 2.x task runner const https = require('https'); return await (async () => { // ── Configuración ──────────────────────────────────────────────────────── const TELEGRAM_TOKEN = '8611913802:AAFlrFtc0vYISOliO_W8B4c-W1ue0hG9Fio'; const TELEGRAM_CHAT = '5138407666'; const RESTART_WEBHOOK = 'https://n8n.chemavx.xyz/webhook/uptime-kuma-restart'; const SERVICES = [ { name: 'n8n', url: 'https://n8n.chemavx.xyz' }, { name: 'openclaw', url: 'https://openclaw.chemavx.xyz' }, { name: 'vaultwarden', url: 'https://vaultwarden.chemavx.xyz' }, { name: 'grafana', url: 'https://grafana.chemavx.xyz' }, { name: 'uptime', url: 'https://uptime.chemavx.xyz' }, { name: 'auth', url: 'https://auth.chemavx.xyz' }, { name: 'home', url: 'https://home.chemavx.xyz' }, { name: 'git', url: 'https://git.chemavx.xyz' }, { name: 'argocd', url: 'https://argocd.chemavx.xyz' }, { name: 'polymarket', url: 'https://polymarket.chemavx.xyz' }, { name: 'ollama', url: 'https://ollama.chemavx.xyz/api/tags' }, ]; // ── Helpers ────────────────────────────────────────────────────────────── const checkService = (service) => { return new Promise((resolve) => { const req = https.get(service.url, (res) => { resolve({ name: service.name, url: service.url, ok: res.statusCode < 400, status: res.statusCode }); res.resume(); }); req.on('error', (err) => { resolve({ name: service.name, url: service.url, ok: false, status: 0, reason: err.message }); }); req.setTimeout(10000, () => { req.destroy(); resolve({ name: service.name, url: service.url, ok: false, status: 0, reason: 'timeout' }); }); }); }; const httpsPost = (urlStr, body) => { return new Promise((resolve) => { const data = JSON.stringify(body); const u = new URL(urlStr); const options = { hostname: u.hostname, path: u.pathname + u.search, method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) }, }; const req = https.request(options, (res) => { res.resume(); resolve(); }); req.on('error', () => resolve()); req.setTimeout(10000, () => { req.destroy(); resolve(); }); req.write(data); req.end(); }); }; const sendTelegram = (text) => { return httpsPost( 'https://api.telegram.org/bot' + TELEGRAM_TOKEN + '/sendMessage', { chat_id: TELEGRAM_CHAT, text, parse_mode: 'Markdown' } ); }; const triggerRestart = (failedServices) => { return httpsPost(RESTART_WEBHOOK, { failed: failedServices }); }; // ── Main ───────────────────────────────────────────────────────────────── const results = await Promise.all(SERVICES.map(checkService)); const failed = results.filter(r => !r.ok); const passed = results.filter(r => r.ok); if (failed.length > 0) { const lines = failed .map(s => '• *' + s.name + '*: ' + (s.reason || ('HTTP ' + s.status)) + ' (' + s.url + ')') .join('\n'); const message = '⚠️ *Health Check Failed*\n\n' + lines + '\n\n_Auto-restart triggered_'; await sendTelegram(message); await triggerRestart(failed); } // ── Return ─────────────────────────────────────────────────────────────── return [{ json: { checked: results.length, passed: passed.length, failed: failed.length, allOk: failed.length === 0, results, }, }]; })();