1+ import logging
12import os
23import secrets
34import socket
45from typing import Any
56
67from django .db import connections
78
9+ logger = logging .getLogger ("steady_queue" )
10+
811
912class Base :
1013 name : str
@@ -51,44 +54,77 @@ def disable_connection_pooling(self):
5154 Disable connection pooling for steady_queue processes.
5255
5356 Connection pooling with psycopg doesn't work with forked processes.
54- This method removes pool configuration from database settings to prevent
55- pool-related errors in steady_queue workers .
57+ This method removes pool configuration from database settings and from
58+ already-instantiated Django connection wrappers .
5659 """
57- import logging
58-
5960 from django .conf import settings
6061
61- logger = logging .getLogger ("steady_queue" )
62-
63- # Disable pooling in database configuration
6462 if hasattr (settings , "DATABASES" ):
6563 for alias , db_config in settings .DATABASES .items ():
66- if db_config .get ("ENGINE" ) == "django.db.backends.postgresql" :
67- # Remove pool configuration if it exists
68- options = db_config .setdefault ("OPTIONS" , {})
69- if "pool" in options :
70- logger .info (
71- "%(name)s disabling connection pooling for database '%(alias)s'" ,
72- {"name" : self .name , "alias" : alias },
73- )
74- del options ["pool" ]
75-
76- # Also disable on any existing connections
64+ if db_config .get ("ENGINE" ) != "django.db.backends.postgresql" :
65+ continue
66+
67+ options = db_config .setdefault ("OPTIONS" , {})
68+ if "pool" in options :
69+ logger .info (
70+ "%(name)s disabling connection pooling for database '%(alias)s'" ,
71+ {"name" : self .name , "alias" : alias },
72+ )
73+ del options ["pool" ]
74+
75+ for alias in connections :
76+ connection = connections [alias ]
77+ if (
78+ connection .settings_dict .get ("ENGINE" )
79+ != "django.db.backends.postgresql"
80+ ):
81+ continue
82+
83+ options = connection .settings_dict .setdefault ("OPTIONS" , {})
84+ if "pool" in options :
85+ logger .debug (
86+ "%(name)s removing pool option from instantiated connection '%(alias)s'" ,
87+ {"name" : self .name , "alias" : alias },
88+ )
89+ del options ["pool" ]
90+
91+ def close_postgresql_connection_pools (self ):
92+ """
93+ Close and clear Django's class-level psycopg pool cache.
94+
95+ Django stores psycopg pools in DatabaseWrapper._connection_pools, so we
96+ must clear those references to avoid inheriting stale pools across fork.
97+ """
98+ closed_pool_maps : set [int ] = set ()
99+
77100 for alias in connections :
78101 connection = connections [alias ]
79- if hasattr (connection , "pool" ) and connection .pool is not None :
102+ if (
103+ connection .settings_dict .get ("ENGINE" )
104+ != "django.db.backends.postgresql"
105+ ):
106+ continue
107+
108+ pool_map = getattr (connection .__class__ , "_connection_pools" , None )
109+ if not isinstance (pool_map , dict ) or id (pool_map ) in closed_pool_maps :
110+ continue
111+
112+ for pool_alias , pool in list (pool_map .items ()):
80113 try :
81- connection .pool .close ()
82- connection .pool = None
114+ pool .close ()
83115 logger .debug (
84- "%(name)s removed existing pool for '%(alias)s'" ,
85- {"name" : self .name , "alias" : alias },
116+ "%(name)s closed psycopg pool for '%(alias)s'" ,
117+ {"name" : self .name , "alias" : pool_alias },
86118 )
87119 except Exception as e :
88120 logger .debug (
89- "%(name)s failed to close existing pool for '%(alias)s': %(e)s" ,
90- {"name" : self .name , "alias" : alias , "e" : e },
121+ "%(name)s failed to close pool for '%(alias)s': %(e)s" ,
122+ {"name" : self .name , "alias" : pool_alias , "e" : e },
91123 )
124+ finally :
125+ pool_map .pop (pool_alias , None )
126+
127+ closed_pool_maps .add (id (pool_map ))
92128
93129 def reset_database_connections (self ):
94130 """
@@ -98,5 +134,5 @@ def reset_database_connections(self):
98134 issues with shared connections between parent and child processes.
99135 """
100136 self .disable_connection_pooling ()
101-
102137 connections .close_all ()
138+ self .close_postgresql_connection_pools ()
0 commit comments