Para quem estiver interessado, aqui está a solução que encontrei, inspirada no comentário de Craig Ringer:
(...) use um cron job para ver quando a conexão foi ativa pela última vez (veja pg_stat_activity) e use pg_terminate_backend para eliminar as antigas.(...)
A solução escolhida fica assim:
- Primeiro, atualizamos para o Postgresql 9.2.
- Em seguida, agendamos um encadeamento para ser executado a cada segundo.
- Quando o encadeamento é executado, ele procura conexões inativas antigas.
- Uma conexão é considerada inativa se for estado é
idle
,idle in transaction
,idle in transaction (aborted)
oudisabled
. - Uma conexão é considerada antiga se for estado permaneceu o mesmo por mais de 5 minutos.
- Uma conexão é considerada inativa se for estado é
- Existem tópicos adicionais que fazem o mesmo que acima. No entanto, esses encadeamentos se conectam ao banco de dados com usuários diferentes.
- Deixamos pelo menos uma conexão aberta para qualquer aplicativo conectado ao nosso banco de dados. (
rank()
função)
Esta é a consulta SQL executada pelo thread:
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