]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
QueuePool: support subsecond timeout
authorJordan Pittier <jordan@gorgias.io>
Wed, 18 Nov 2020 14:57:43 +0000 (09:57 -0500)
committerGord Thompson <gord@gordthompson.com>
Sat, 21 Nov 2020 13:47:11 +0000 (06:47 -0700)
Fixes: #5719
<!-- Provide a general summary of your proposed changes in the Title field above -->

### Description
Make it explicit in the documentation and in the default value for the 'timeout'
parameter that `timeout` can be a float. Because Python timing is not
very accurate, warn about the precision.

### Checklist
<!-- go over following points. check them with an `x` if they do apply, (they turn into clickable checkboxes once the PR is submitted, so no need to do everything at once)

-->

This pull request is:

- [ ] A documentation / typographical error fix
- Good to go, no issue or tests are needed
- [x] A short code fix
- please include the issue number, and create an issue if none exists, which
  must include a complete example of the issue.  one line code fixes without an
  issue and demonstration will not be accepted.
- Please include: `Fixes: #<issue number>` in the commit message
- please include tests.   one line code fixes without tests will not be accepted.
- [ ] A new feature implementation
- please include the issue number, and create an issue if none exists, which must
  include a complete example of how the feature would look.
- Please include: `Fixes: #<issue number>` in the commit message
- please include tests.

**Have a nice day!**

Closes: #5710
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/5710
Pull-request-sha: 5f4eef8b4aba756d32e14ea41f71ef2919c26b84

Change-Id: I462524b1624ca5cc76d083a1d58e5dc89501c1a9

doc/build/changelog/unreleased_14/5719.rst [new file with mode: 0644]
lib/sqlalchemy/engine/create.py
lib/sqlalchemy/pool/impl.py
test/engine/test_pool.py

diff --git a/doc/build/changelog/unreleased_14/5719.rst b/doc/build/changelog/unreleased_14/5719.rst
new file mode 100644 (file)
index 0000000..3f0d73e
--- /dev/null
@@ -0,0 +1,6 @@
+.. change::
+    :tags: pool, tests, usecase
+    :tickets: 5582
+
+    Improve documentation and add test for sub-second pool timeouts.
+    Pull request courtesy Jordan Pittier.
index 786f8f5d6ab57cebe1391484aa334df74fdbf29f..b48cead791a495ddbf83de283b719fb8bd65dd36 100644 (file)
@@ -440,9 +440,11 @@ def create_engine(url, **kwargs):
 
             :paramref:`_pool.Pool.reset_on_return`
 
-    :param pool_timeout=30: number of seconds to wait before giving
+    :param pool_timeout=30.0: number of seconds to wait before giving
         up on getting a connection from the pool. This is only used
-        with :class:`~sqlalchemy.pool.QueuePool`.
+        with :class:`~sqlalchemy.pool.QueuePool`. This can be a float but is
+        subject to the limitations of Python time functions which may not be
+        reliable in the tens of milliseconds.
 
     :param pool_use_lifo=False: use LIFO (last-in-first-out) when retrieving
         connections from :class:`.QueuePool` instead of FIFO
index fc543053d31b5b53d1eced1893f07e375b0435aa..38afbc7a1a37a6090e17831439bd1670c76aaae6 100644 (file)
@@ -40,7 +40,7 @@ class QueuePool(Pool):
         creator,
         pool_size=5,
         max_overflow=10,
-        timeout=30,
+        timeout=30.0,
         use_lifo=False,
         **kw
     ):
@@ -73,7 +73,9 @@ class QueuePool(Pool):
           connections. Defaults to 10.
 
         :param timeout: The number of seconds to wait before giving up
-          on returning a connection. Defaults to 30.
+          on returning a connection. Defaults to 30.0. This can be a float
+          but is subject to the limitations of Python time functions which
+          may not be reliable in the tens of milliseconds.
 
         :param use_lifo: use LIFO (last-in-first-out) when retrieving
           connections instead of FIFO (first-in-first-out). Using LIFO, a
@@ -129,7 +131,7 @@ class QueuePool(Pool):
             else:
                 raise exc.TimeoutError(
                     "QueuePool limit of size %d overflow %d reached, "
-                    "connection timed out, timeout %d"
+                    "connection timed out, timeout %0.2f"
                     % (self.size(), self.overflow(), self._timeout),
                     code="3o7r",
                 )
index 9ea3065b033d50fbb50bc55bd88560aeeb8d5ec0..1a49cf4b92fa227780bf9fb87f989ea80921226c 100644 (file)
@@ -14,6 +14,7 @@ from sqlalchemy.testing import assert_raises
 from sqlalchemy.testing import assert_raises_context_ok
 from sqlalchemy.testing import assert_raises_message
 from sqlalchemy.testing import eq_
+from sqlalchemy.testing import expect_raises
 from sqlalchemy.testing import fixtures
 from sqlalchemy.testing import is_
 from sqlalchemy.testing import is_not
@@ -886,6 +887,17 @@ class QueuePoolTest(PoolTestBase):
         assert_raises(tsa.exc.TimeoutError, p.connect)
         assert int(time.time() - now) == 2
 
+    @testing.requires.timing_intensive
+    def test_timeout_subsecond_precision(self):
+        p = self._queuepool_fixture(pool_size=1, max_overflow=0, timeout=0.5)
+        c1 = p.connect()  # noqa
+        with expect_raises(tsa.exc.TimeoutError):
+            now = time.time()
+            c2 = p.connect()  # noqa
+        # Python timing is not very accurate, the time diff should be very
+        # close to 0.5s but we give 200ms of slack.
+        assert 0.3 <= time.time() - now <= 0.7, "Pool timeout not respected"
+
     @testing.requires.threading_with_mock
     @testing.requires.timing_intensive
     def test_timeout_race(self):