{ config, lib, pkgs, ... }: let txPort = config.m3ta.ports.get "pgbouncer-tx"; sessionPort = config.m3ta.ports.get "pgbouncer-session"; pgPort = config.m3ta.ports.get "postgres"; # Podman-Bridge-IP des Hosts hostBridgeIP = "10.89.0.1"; commonSettings = { listen_addr = "127.0.0.1,${hostBridgeIP}"; auth_type = "scram-sha-256"; auth_file = config.age.secrets.pgbouncer-userlist.path; admin_users = "sascha_koenig"; stats_users = "sascha_koenig"; log_connections = 1; log_disconnections = 1; server_reset_query = "DISCARD ALL"; server_check_query = "SELECT 1"; server_check_delay = 30; server_tls_sslmode = "prefer"; }; mkDatabases = dbs: lib.listToAttrs (map (db: lib.nameValuePair db "host=127.0.0.1 port=${toString pgPort} dbname=${db}") dbs); in { services.pgbouncer = { enable = true; settings = { pgbouncer = commonSettings // { listen_port = txPort; pool_mode = "transaction"; max_client_conn = 1000; default_pool_size = 10; min_pool_size = 2; reserve_pool_size = 3; reserve_pool_timeout = 3; max_prepared_statements = 200; }; databases = mkDatabases [ "baserow" "litellm" "librechat_rag" "librechat_rag_dev" "metabase" "az_kpi_raw" ]; }; }; systemd.services.pgbouncer = { after = ["postgresql.service"]; requires = ["postgresql.service"]; }; environment.etc."pgbouncer/pgbouncer-session.ini".text = let dbLines = lib.concatStringsSep "\n" (lib.mapAttrsToList (name: conn: "${name} = ${conn}") (mkDatabases [ "outline" "zammad" "zammad_hr" "vaultwarden" "dash" ])); in '' [databases] ${dbLines} [pgbouncer] listen_addr = ${commonSettings.listen_addr} listen_port = ${toString sessionPort} pool_mode = session auth_type = ${commonSettings.auth_type} auth_file = ${config.age.secrets.pgbouncer-userlist.path} admin_users = ${commonSettings.admin_users} stats_users = ${commonSettings.stats_users} max_client_conn = 300 # session-Mode: 1 Client-Conn = 1 Server-Conn. zammad_hr haelt via mehrere # Prozesse (rails+scheduler+websocket) real ~15 Conns -> pro (user,db) 15. # outline/vaultwarden schoepfen das nie aus (eigene Slots je user,db). default_pool_size = 15 min_pool_size = 1 query_wait_timeout = 30 log_connections = 1 log_disconnections = 1 server_reset_query = DISCARD ALL server_check_query = SELECT 1 server_check_delay = 30 server_tls_sslmode = prefer # PID/Socket getrennt von der Haupt-Instanz halten. pidfile = /run/pgbouncer-session/pgbouncer.pid unix_socket_dir = /run/pgbouncer-session ''; systemd.services.pgbouncer-session = { description = "PgBouncer (session pool) for prepared-statement apps"; after = ["postgresql.service"]; requires = ["postgresql.service"]; wantedBy = ["multi-user.target"]; serviceConfig = { User = "pgbouncer"; Group = "pgbouncer"; RuntimeDirectory = "pgbouncer-session"; ExecStart = "${pkgs.pgbouncer}/bin/pgbouncer /etc/pgbouncer/pgbouncer-session.ini"; Restart = "on-failure"; RestartSec = 5; }; }; networking.firewall.extraCommands = '' iptables -A INPUT -p tcp -s 127.0.0.1 --dport ${toString txPort} -j ACCEPT iptables -A INPUT -p tcp -s 10.89.0.0/24 --dport ${toString txPort} -j ACCEPT iptables -A INPUT -p tcp -s 127.0.0.1 --dport ${toString sessionPort} -j ACCEPT iptables -A INPUT -p tcp -s 10.89.0.0/24 --dport ${toString sessionPort} -j ACCEPT ''; }