Skip to content

Commit 171bb2f

Browse files
committed
add experimental support for connection closed listeners
1 parent 2c99beb commit 171bb2f

File tree

1 file changed

+34
-2
lines changed

1 file changed

+34
-2
lines changed

asyncpg/connection.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ class Connection(metaclass=ConnectionMeta):
4646
'_listeners', '_server_version', '_server_caps',
4747
'_intro_query', '_reset_query', '_proxy',
4848
'_stmt_exclusive_section', '_config', '_params', '_addr',
49-
'_log_listeners', '_cancellations', '_source_traceback',
50-
'__weakref__')
49+
'_log_listeners', '_cleanup_listeners', '_cancellations',
50+
'_source_traceback', '__weakref__')
5151

5252
def __init__(self, protocol, transport, loop,
5353
addr: (str, int) or str,
@@ -78,6 +78,7 @@ def __init__(self, protocol, transport, loop,
7878
self._listeners = {}
7979
self._log_listeners = set()
8080
self._cancellations = set()
81+
self._cleanup_listeners = set()
8182

8283
settings = self._protocol.get_settings()
8384
ver_string = settings.server_version
@@ -178,6 +179,19 @@ def remove_log_listener(self, callback):
178179
"""
179180
self._log_listeners.discard(callback)
180181

182+
def add_close_listener(self, callback):
183+
"""Add a listener that will be called when the the connection is closing.
184+
185+
:param callable callback:
186+
A callable receiving one argument:
187+
**connection**: a Connection the callback is registered with.
188+
"""
189+
self._cleanup_listeners.add(callback)
190+
191+
def remove_close_listener(self, callback):
192+
"""Remove a listening callback for the connection closing."""
193+
self._cleanup_listeners.discard(callback)
194+
181195
def get_server_pid(self):
182196
"""Return the PID of the Postgres server the connection is bound to."""
183197
return self._protocol.get_server_pid()
@@ -1120,6 +1134,7 @@ def _abort(self):
11201134
self._protocol = None
11211135

11221136
def _cleanup(self):
1137+
self._call_cleanup_listeners()
11231138
# Free the resources associated with this connection.
11241139
# This must be called when a connection is terminated.
11251140

@@ -1237,6 +1252,23 @@ def _call_log_listener(self, cb, con_ref, message):
12371252
'exception': ex
12381253
})
12391254

1255+
def _call_cleanup_listeners(self):
1256+
if not self._cleanup_listeners:
1257+
return
1258+
1259+
con_ref = self._unwrap()
1260+
for cb in self._cleanup_listeners:
1261+
try:
1262+
cb(con_ref)
1263+
except Exception as ex:
1264+
self._loop.call_exception_handler({
1265+
'message': 'Unhandled exception in asyncpg connection '
1266+
'connection closed callback {!r}'.format(cb),
1267+
'exception': ex
1268+
})
1269+
1270+
self._cleanup_listeners.clear()
1271+
12401272
def _process_notification(self, pid, channel, payload):
12411273
if channel not in self._listeners:
12421274
return

0 commit comments

Comments
 (0)