1# pool/events.py
2# Copyright (C) 2005-2024 the SQLAlchemy authors and contributors
3# <see AUTHORS file>
4#
5# This module is part of SQLAlchemy and is released under
6# the MIT License: https://www.opensource.org/licenses/mit-license.php
7
8from .base import Pool
9from .. import event
10from ..engine.base import Engine
11
12
13class PoolEvents(event.Events):
14 """Available events for :class:`_pool.Pool`.
15
16 The methods here define the name of an event as well
17 as the names of members that are passed to listener
18 functions.
19
20 e.g.::
21
22 from sqlalchemy import event
23
24 def my_on_checkout(dbapi_conn, connection_rec, connection_proxy):
25 "handle an on checkout event"
26
27 event.listen(Pool, 'checkout', my_on_checkout)
28
29 In addition to accepting the :class:`_pool.Pool` class and
30 :class:`_pool.Pool` instances, :class:`_events.PoolEvents` also accepts
31 :class:`_engine.Engine` objects and the :class:`_engine.Engine` class as
32 targets, which will be resolved to the ``.pool`` attribute of the
33 given engine or the :class:`_pool.Pool` class::
34
35 engine = create_engine("postgresql://scott:tiger@localhost/test")
36
37 # will associate with engine.pool
38 event.listen(engine, 'checkout', my_on_checkout)
39
40 """
41
42 _target_class_doc = "SomeEngineOrPool"
43 _dispatch_target = Pool
44
45 @classmethod
46 def _accept_with(cls, target):
47 if isinstance(target, type):
48 if issubclass(target, Engine):
49 return Pool
50 elif issubclass(target, Pool):
51 return target
52 elif isinstance(target, Engine):
53 return target.pool
54 elif isinstance(target, Pool):
55 return target
56 elif hasattr(target, "dispatch") and hasattr(
57 target.dispatch._events, "_no_async_engine_events"
58 ):
59 target.dispatch._events._no_async_engine_events()
60 else:
61 return None
62
63 @classmethod
64 def _listen(cls, event_key, **kw):
65 target = event_key.dispatch_target
66
67 kw.setdefault("asyncio", target._is_asyncio)
68
69 event_key.base_listen(**kw)
70
71 def connect(self, dbapi_connection, connection_record):
72 """Called at the moment a particular DBAPI connection is first
73 created for a given :class:`_pool.Pool`.
74
75 This event allows one to capture the point directly after which
76 the DBAPI module-level ``.connect()`` method has been used in order
77 to produce a new DBAPI connection.
78
79 :param dbapi_connection: a DBAPI connection.
80 The :attr:`._ConnectionRecord.dbapi_connection` attribute.
81
82 :param connection_record: the :class:`._ConnectionRecord` managing the
83 DBAPI connection.
84
85 """
86
87 def first_connect(self, dbapi_connection, connection_record):
88 """Called exactly once for the first time a DBAPI connection is
89 checked out from a particular :class:`_pool.Pool`.
90
91 The rationale for :meth:`_events.PoolEvents.first_connect`
92 is to determine
93 information about a particular series of database connections based
94 on the settings used for all connections. Since a particular
95 :class:`_pool.Pool`
96 refers to a single "creator" function (which in terms
97 of a :class:`_engine.Engine`
98 refers to the URL and connection options used),
99 it is typically valid to make observations about a single connection
100 that can be safely assumed to be valid about all subsequent
101 connections, such as the database version, the server and client
102 encoding settings, collation settings, and many others.
103
104 :param dbapi_connection: a DBAPI connection.
105 The :attr:`._ConnectionRecord.dbapi_connection` attribute.
106
107 :param connection_record: the :class:`._ConnectionRecord` managing the
108 DBAPI connection.
109
110 """
111
112 def checkout(self, dbapi_connection, connection_record, connection_proxy):
113 """Called when a connection is retrieved from the Pool.
114
115 :param dbapi_connection: a DBAPI connection.
116 The :attr:`._ConnectionRecord.dbapi_connection` attribute.
117
118 :param connection_record: the :class:`._ConnectionRecord` managing the
119 DBAPI connection.
120
121 :param connection_proxy: the :class:`._ConnectionFairy` object which
122 will proxy the public interface of the DBAPI connection for the
123 lifespan of the checkout.
124
125 If you raise a :class:`~sqlalchemy.exc.DisconnectionError`, the current
126 connection will be disposed and a fresh connection retrieved.
127 Processing of all checkout listeners will abort and restart
128 using the new connection.
129
130 .. seealso:: :meth:`_events.ConnectionEvents.engine_connect`
131 - a similar event
132 which occurs upon creation of a new :class:`_engine.Connection`.
133
134 """
135
136 def checkin(self, dbapi_connection, connection_record):
137 """Called when a connection returns to the pool.
138
139 Note that the connection may be closed, and may be None if the
140 connection has been invalidated. ``checkin`` will not be called
141 for detached connections. (They do not return to the pool.)
142
143 :param dbapi_connection: a DBAPI connection.
144 The :attr:`._ConnectionRecord.dbapi_connection` attribute.
145
146 :param connection_record: the :class:`._ConnectionRecord` managing the
147 DBAPI connection.
148
149 """
150
151 def reset(self, dbapi_connection, connection_record):
152 """Called before the "reset" action occurs for a pooled connection.
153
154 This event represents when the ``rollback()`` method is called on the
155 DBAPI connection before it is returned to the pool or discarded. A
156 custom "reset" strategy may be implemented using this event hook, which
157 may also be combined with disabling the default "reset" behavior using
158 the :paramref:`_pool.Pool.reset_on_return` parameter.
159
160 The primary difference between the :meth:`_events.PoolEvents.reset` and
161 :meth:`_events.PoolEvents.checkin` events are that
162 :meth:`_events.PoolEvents.reset` is called not just for pooled
163 connections that are being returned to the pool, but also for
164 connections that were detached using the
165 :meth:`_engine.Connection.detach` method.
166
167 Note that the event **is not** invoked for connections that were
168 invalidated using :meth:`_engine.Connection.invalidate`. These
169 events may be intercepted using the :meth:`.PoolEvents.soft_invalidate`
170 and :meth:`.PoolEvents.invalidate` event hooks, and all "connection
171 close" events may be intercepted using :meth:`.PoolEvents.close`.
172 The :meth:`_events.PoolEvents.reset` event is usually followed by the
173 :meth:`_events.PoolEvents.checkin` event, except in those
174 cases where the connection is discarded immediately after reset.
175
176 In the 1.4 series, the event is also not invoked for asyncio
177 connections that are being garbage collected without their being
178 explicitly returned to the pool. This is due to the lack of an event
179 loop which prevents "reset" operations from taking place. Version 2.0
180 will feature an enhanced version of :meth:`.PoolEvents.reset` which is
181 invoked in this scenario while passing additional contextual
182 information indicating that an event loop is not guaranteed
183 to be present.
184
185 :param dbapi_connection: a DBAPI connection.
186 The :attr:`._ConnectionRecord.dbapi_connection` attribute.
187
188 :param connection_record: the :class:`._ConnectionRecord` managing the
189 DBAPI connection.
190
191 .. seealso::
192
193 :meth:`_events.ConnectionEvents.rollback`
194
195 :meth:`_events.ConnectionEvents.commit`
196
197 """
198
199 def invalidate(self, dbapi_connection, connection_record, exception):
200 """Called when a DBAPI connection is to be "invalidated".
201
202 This event is called any time the :meth:`._ConnectionRecord.invalidate`
203 method is invoked, either from API usage or via "auto-invalidation",
204 without the ``soft`` flag.
205
206 The event occurs before a final attempt to call ``.close()`` on the
207 connection occurs.
208
209 :param dbapi_connection: a DBAPI connection.
210 The :attr:`._ConnectionRecord.dbapi_connection` attribute.
211
212 :param connection_record: the :class:`._ConnectionRecord` managing the
213 DBAPI connection.
214
215 :param exception: the exception object corresponding to the reason
216 for this invalidation, if any. May be ``None``.
217
218 .. versionadded:: 0.9.2 Added support for connection invalidation
219 listening.
220
221 .. seealso::
222
223 :ref:`pool_connection_invalidation`
224
225 """
226
227 def soft_invalidate(self, dbapi_connection, connection_record, exception):
228 """Called when a DBAPI connection is to be "soft invalidated".
229
230 This event is called any time the :meth:`._ConnectionRecord.invalidate`
231 method is invoked with the ``soft`` flag.
232
233 Soft invalidation refers to when the connection record that tracks
234 this connection will force a reconnect after the current connection
235 is checked in. It does not actively close the dbapi_connection
236 at the point at which it is called.
237
238 .. versionadded:: 1.0.3
239
240 :param dbapi_connection: a DBAPI connection.
241 The :attr:`._ConnectionRecord.dbapi_connection` attribute.
242
243 :param connection_record: the :class:`._ConnectionRecord` managing the
244 DBAPI connection.
245
246 :param exception: the exception object corresponding to the reason
247 for this invalidation, if any. May be ``None``.
248
249 """
250
251 def close(self, dbapi_connection, connection_record):
252 """Called when a DBAPI connection is closed.
253
254 The event is emitted before the close occurs.
255
256 The close of a connection can fail; typically this is because
257 the connection is already closed. If the close operation fails,
258 the connection is discarded.
259
260 The :meth:`.close` event corresponds to a connection that's still
261 associated with the pool. To intercept close events for detached
262 connections use :meth:`.close_detached`.
263
264 .. versionadded:: 1.1
265
266 :param dbapi_connection: a DBAPI connection.
267 The :attr:`._ConnectionRecord.dbapi_connection` attribute.
268
269 :param connection_record: the :class:`._ConnectionRecord` managing the
270 DBAPI connection.
271
272 """
273
274 def detach(self, dbapi_connection, connection_record):
275 """Called when a DBAPI connection is "detached" from a pool.
276
277 This event is emitted after the detach occurs. The connection
278 is no longer associated with the given connection record.
279
280 .. versionadded:: 1.1
281
282 :param dbapi_connection: a DBAPI connection.
283 The :attr:`._ConnectionRecord.dbapi_connection` attribute.
284
285 :param connection_record: the :class:`._ConnectionRecord` managing the
286 DBAPI connection.
287
288 """
289
290 def close_detached(self, dbapi_connection):
291 """Called when a detached DBAPI connection is closed.
292
293 The event is emitted before the close occurs.
294
295 The close of a connection can fail; typically this is because
296 the connection is already closed. If the close operation fails,
297 the connection is discarded.
298
299 .. versionadded:: 1.1
300
301 :param dbapi_connection: a DBAPI connection.
302 The :attr:`._ConnectionRecord.dbapi_connection` attribute.
303
304 """