Dla zainteresowanych, oto rozwiązanie, które wymyśliłem, zainspirowane komentarzem Craiga Ringera:
(...) użyj zadania cron, aby sprawdzić, kiedy połączenie było ostatnio aktywne (zobacz pg_stat_activity) i użyj pg_terminate_backend, aby zabić stare.(...)
Wybrane rozwiązanie sprowadza się do tego:
- Najpierw aktualizujemy do Postgresql 9.2.
- Następnie planujemy uruchamianie wątku co sekundę.
- Gdy wątek działa, szuka starych nieaktywnych połączeń.
- Połączenie jest uważane za nieaktywne jeśli jego stan jest albo
idle
,idle in transaction
,idle in transaction (aborted)
lubdisabled
. - Połączenie jest uważane za stare jeśli jego stan pozostał taki sam przez ponad 5 minut.
- Połączenie jest uważane za nieaktywne jeśli jego stan jest albo
- Istnieją dodatkowe wątki, które robią to samo, co powyżej. Jednak te wątki łączą się z bazą danych z innym użytkownikiem.
- Zostawiamy co najmniej jedno połączenie otwarte dla dowolnej aplikacji połączonej z naszą bazą danych. (
rank()
funkcja)
To jest zapytanie SQL wykonywane przez wątek:
WITH inactive_connections AS (
SELECT
pid,
rank() over (partition by client_addr order by backend_start ASC) as rank
FROM
pg_stat_activity
WHERE
-- Exclude the thread owned connection (ie no auto-kill)
pid <> pg_backend_pid( )
AND
-- Exclude known applications connections
application_name !~ '(?:psql)|(?:pgAdmin.+)'
AND
-- Include connections to the same database the thread is connected to
datname = current_database()
AND
-- Include connections using the same thread username connection
usename = current_user
AND
-- Include inactive connections only
state in ('idle', 'idle in transaction', 'idle in transaction (aborted)', 'disabled')
AND
-- Include old connections (found with the state_change field)
current_timestamp - state_change > interval '5 minutes'
)
SELECT
pg_terminate_backend(pid)
FROM
inactive_connections
WHERE
rank > 1 -- Leave one connection for each application connected to the database