diff --git a/backend/check-connections.js b/backend/check-connections.js new file mode 100644 index 0000000..35d2541 --- /dev/null +++ b/backend/check-connections.js @@ -0,0 +1,86 @@ +#!/usr/bin/env node + +/** + * Script zum Prüfen und Bereinigen von PostgreSQL-Verbindungen + */ + +import './config/loadEnv.js'; +import { sequelize } from './utils/sequelize.js'; + +async function main() { + try { + console.log('🔍 Prüfe PostgreSQL-Verbindungen...\n'); + + // Prüfe aktive Verbindungen + const [connections] = await sequelize.query(` + SELECT + count(*) as total, + count(*) FILTER (WHERE state = 'active') as active, + count(*) FILTER (WHERE state = 'idle') as idle, + count(*) FILTER (WHERE state = 'idle in transaction') as idle_in_transaction, + count(*) FILTER (WHERE usename = current_user) as my_connections + FROM pg_stat_activity + WHERE datname = current_database(); + `); + + console.log('📊 Verbindungsstatistik:'); + console.log(` Gesamt: ${connections[0].total}`); + console.log(` Aktiv: ${connections[0].active}`); + console.log(` Idle: ${connections[0].idle}`); + console.log(` Idle in Transaction: ${connections[0].idle_in_transaction}`); + console.log(` Meine Verbindungen: ${connections[0].my_connections}\n`); + + // Prüfe max_connections Limit + const [maxConn] = await sequelize.query(` + SELECT setting::int as max_connections + FROM pg_settings + WHERE name = 'max_connections'; + `); + console.log(`📈 Max Connections Limit: ${maxConn[0].max_connections}`); + console.log(`📉 Verfügbare Connections: ${maxConn[0].max_connections - connections[0].total}\n`); + + // Zeige alte idle Verbindungen + const [oldConnections] = await sequelize.query(` + SELECT + pid, + usename, + application_name, + state, + state_change, + now() - state_change as idle_duration, + query + FROM pg_stat_activity + WHERE datname = current_database() + AND state = 'idle' + AND state_change < now() - interval '1 minute' + ORDER BY state_change ASC + LIMIT 10; + `); + + if (oldConnections.length > 0) { + console.log(`⚠️ Gefunden ${oldConnections.length} alte idle Verbindungen (> 1 Minute):`); + oldConnections.forEach(conn => { + console.log(` PID: ${conn.pid}, User: ${conn.usename}, Idle seit: ${conn.idle_duration}`); + }); + console.log('\n💡 Tipp: Du kannst alte Verbindungen beenden mit:'); + console.log(' SELECT pg_terminate_backend(pid) FROM pg_stat_activity'); + console.log(' WHERE datname = current_database() AND state = \'idle\' AND state_change < now() - interval \'5 minutes\';\n'); + } + + // Prüfe ob wir nahe am Limit sind + const usagePercent = (connections[0].total / maxConn[0].max_connections) * 100; + if (usagePercent > 80) { + console.log(`⚠️ WARNUNG: ${usagePercent.toFixed(1)}% der verfügbaren Verbindungen werden verwendet!`); + console.log(' Es könnte sein, dass nicht genug Verbindungen verfügbar sind.\n'); + } + + await sequelize.close(); + process.exit(0); + + } catch (error) { + console.error('❌ Fehler:', error.message); + process.exit(1); + } +} + +main(); diff --git a/backend/cleanup-connections.js b/backend/cleanup-connections.js new file mode 100644 index 0000000..3b90029 --- /dev/null +++ b/backend/cleanup-connections.js @@ -0,0 +1,55 @@ +#!/usr/bin/env node + +/** + * Script zum Bereinigen von alten/idle PostgreSQL-Verbindungen + */ + +import './config/loadEnv.js'; +import { sequelize } from './utils/sequelize.js'; + +async function main() { + try { + console.log('🧹 Bereinige alte PostgreSQL-Verbindungen...\n'); + + // Beende idle Verbindungen, die älter als 5 Minuten sind (außer unserer eigenen) + const [result] = await sequelize.query(` + SELECT pg_terminate_backend(pid) as terminated + FROM pg_stat_activity + WHERE datname = current_database() + AND pid <> pg_backend_pid() + AND state = 'idle' + AND state_change < now() - interval '5 minutes'; + `); + + const terminated = result.filter(r => r.terminated).length; + console.log(`✅ ${terminated} alte idle Verbindungen wurden beendet\n`); + + // Zeige verbleibende Verbindungen + const [connections] = await sequelize.query(` + SELECT + count(*) as total, + count(*) FILTER (WHERE state = 'active') as active, + count(*) FILTER (WHERE state = 'idle') as idle + FROM pg_stat_activity + WHERE datname = current_database(); + `); + + console.log('📊 Verbleibende Verbindungen:'); + console.log(` Gesamt: ${connections[0].total}`); + console.log(` Aktiv: ${connections[0].active}`); + console.log(` Idle: ${connections[0].idle}\n`); + + await sequelize.close(); + process.exit(0); + + } catch (error) { + console.error('❌ Fehler:', error.message); + if (error.message.includes('SUPERUSER')) { + console.error('\n💡 Tipp: Du benötigst Superuser-Rechte oder musst warten, bis Verbindungen freigegeben werden.'); + console.error(' Versuche es in ein paar Minuten erneut.'); + } + process.exit(1); + } +} + +main(); diff --git a/backend/package.json b/backend/package.json index 5182d6c..3fb543f 100644 --- a/backend/package.json +++ b/backend/package.json @@ -10,6 +10,8 @@ "start-daemon": "node daemonServer.js", "sync-db": "node sync-database.js", "sync-tables": "node sync-tables-only.js", + "check-connections": "node check-connections.js", + "cleanup-connections": "node cleanup-connections.js", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [],