#!/usr/bin/env node /** * Liest backend/sql/diagnostics/falukant_town_product_worth_stats.sql und gibt eine Tabelle aus. * * cd backend && npm run diag:town-worth * * SSH-Tunnel: DB_HOST=127.0.0.1, DB_PORT= — siehe backend/env.example * Hängt die Verbindung: Tunnel läuft? Sonst TLS (DB_SSL=1), falscher Port, Firewall. */ import { readFileSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; import { dirname, join } from 'node:path'; const __dirname = dirname(fileURLToPath(import.meta.url)); const sqlPath = join(__dirname, '../sql/diagnostics/falukant_town_product_worth_stats.sql'); const QUERY_TIMEOUT_MS = Number.parseInt(process.env.DIAG_QUERY_TIMEOUT_MS || '60000', 10); const AUTH_TIMEOUT_MS = Number.parseInt(process.env.DIAG_AUTH_TIMEOUT_MS || '25000', 10); process.env.QUIET_ENV_LOGS = process.env.QUIET_ENV_LOGS || '1'; process.env.DOTENV_CONFIG_QUIET = process.env.DOTENV_CONFIG_QUIET || '1'; if (!process.env.DB_CONNECT_TIMEOUT_MS) { process.env.DB_CONNECT_TIMEOUT_MS = '15000'; } await import('../config/loadEnv.js'); const { sequelize } = await import('../utils/sequelize.js'); /** Promise.race + Timeout, aber Timer wird bei Erfolg cleared — sonst blockiert setTimeout(60s) den Prozess. */ function withTimeout(promise, ms, onTimeoutError) { let timerId; const timeoutPromise = new Promise((_, reject) => { timerId = setTimeout(() => reject(new Error(onTimeoutError)), ms); }); return Promise.race([promise, timeoutPromise]).finally(() => { clearTimeout(timerId); }); } function raceQuery(sql) { return withTimeout( sequelize.query(sql), QUERY_TIMEOUT_MS, `Abfrage-Timeout nach ${QUERY_TIMEOUT_MS} ms (DIAG_QUERY_TIMEOUT_MS)` ); } function raceAuth() { return withTimeout( sequelize.authenticate(), AUTH_TIMEOUT_MS, `authenticate() Timeout nach ${AUTH_TIMEOUT_MS} ms — TCP/TLS zu PostgreSQL kommt nicht zustande (DIAG_AUTH_TIMEOUT_MS).` ); } function printConnectionHints() { const port = process.env.DB_PORT || '5432'; const host = process.env.DB_HOST || '?'; const local = host === '127.0.0.1' || host === 'localhost' || host === '::1'; console.error(''); console.error('[diag] Mögliche Ursachen:'); if (local) { console.error(' • SSH-Tunnel: Läuft z. B. ssh -L ' + port + ':127.0.0.1:5432 …? Dann DB_HOST=127.0.0.1 DB_PORT=' + port + ' (DB_SSL meist aus).'); console.error(' • Falscher lokaler Forward-Port in .env (DB_PORT).'); } else { console.error(' • PostgreSQL erwartet TLS: in .env DB_SSL=1 setzen (ggf. DB_SSL_REJECT_UNAUTHORIZED=0 bei selbstsigniert).'); console.error(' • Falscher Port: DB_PORT=' + port + ' prüfen.'); console.error(' • Server-Firewall: deine IP muss für Port', port, 'auf', host, 'freigeschaltet sein.'); } console.error(' • Test: nc -zv', host, port); console.error(''); } try { const sql = readFileSync(sqlPath, 'utf8'); const host = process.env.DB_HOST || '(unbekannt)'; const t0 = Date.now(); console.log(''); console.log('[diag] PostgreSQL: authenticate() … (Host:', host + ', Port:', process.env.DB_PORT || '5432', ', DB_SSL:', process.env.DB_SSL === '1' ? '1' : '0', ')'); console.log(''); await raceAuth(); console.log('[diag] authenticate() ok nach', Date.now() - t0, 'ms'); await sequelize.query("SET statement_timeout = '30s'"); const t1 = Date.now(); const [rows] = await raceQuery(sql); console.log('[diag] SELECT ok nach', Date.now() - t1, 'ms (gesamt', Date.now() - t0, 'ms)'); console.log(''); console.table(rows); await sequelize.close(); process.exit(0); } catch (err) { console.error(err.message || err); printConnectionHints(); try { await sequelize.close(); } catch (_) {} process.exit(1); }