diff options
| author | Jordan Pittier <jordan@gorgias.io> | 2020-11-18 09:57:43 -0500 |
|---|---|---|
| committer | Gord Thompson <gord@gordthompson.com> | 2020-11-21 06:47:11 -0700 |
| commit | 2b746211188642333b3151bfbb429b236a1559d1 (patch) | |
| tree | 21c2591d4ea5d50c630bc1dd638a4eba069384b3 | |
| parent | 17bdc3066c8e5803fdfce6c40f6f04c291e9851d (diff) | |
| download | sqlalchemy-2b746211188642333b3151bfbb429b236a1559d1.tar.gz | |
QueuePool: support subsecond timeout
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
| -rw-r--r-- | doc/build/changelog/unreleased_14/5719.rst | 6 | ||||
| -rw-r--r-- | lib/sqlalchemy/engine/create.py | 6 | ||||
| -rw-r--r-- | lib/sqlalchemy/pool/impl.py | 8 | ||||
| -rw-r--r-- | test/engine/test_pool.py | 12 |
4 files changed, 27 insertions, 5 deletions
diff --git a/doc/build/changelog/unreleased_14/5719.rst b/doc/build/changelog/unreleased_14/5719.rst new file mode 100644 index 000000000..3f0d73e5d --- /dev/null +++ b/doc/build/changelog/unreleased_14/5719.rst @@ -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. diff --git a/lib/sqlalchemy/engine/create.py b/lib/sqlalchemy/engine/create.py index 786f8f5d6..b48cead79 100644 --- a/lib/sqlalchemy/engine/create.py +++ b/lib/sqlalchemy/engine/create.py @@ -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 diff --git a/lib/sqlalchemy/pool/impl.py b/lib/sqlalchemy/pool/impl.py index fc543053d..38afbc7a1 100644 --- a/lib/sqlalchemy/pool/impl.py +++ b/lib/sqlalchemy/pool/impl.py @@ -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", ) diff --git a/test/engine/test_pool.py b/test/engine/test_pool.py index 9ea3065b0..1a49cf4b9 100644 --- a/test/engine/test_pool.py +++ b/test/engine/test_pool.py @@ -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): |
