Skip to content

Commit 9d84126

Browse files
Internal change to ensure that pools are closed gracefully when the main
thread terminates.
1 parent 91e22e2 commit 9d84126

File tree

2 files changed

+27
-7
lines changed

2 files changed

+27
-7
lines changed

doc/src/release_notes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ Thin Mode Changes
2727
#) Fixed bug when fetch variables contain output converters and a query is
2828
re-executed
2929
(`issue 271 <https://github.com/oracle/python-oracledb/issues/271>`__).
30+
#) Internal change to ensure that pools are closed gracefully when the main
31+
thread terminates.
3032
#) Internal change to slightly improve performance of LOB reads and writes.
3133
#) Corrected typing declaration for :meth:`oracledb.connect_async()`.
3234

src/oracledb/impl/thin/pool.pyx

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#------------------------------------------------------------------------------
2-
# Copyright (c) 2020, 2023, Oracle and/or its affiliates.
2+
# Copyright (c) 2020, 2024, Oracle and/or its affiliates.
33
#
44
# This software is dual-licensed to you under the Universal Permissive License
55
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
@@ -442,8 +442,7 @@ cdef class ThinPoolImpl(BaseThinPoolImpl):
442442
super().__init__(dsn, params)
443443
self._condition = threading.Condition()
444444
self._bg_task_condition = threading.Condition()
445-
self._bg_task = threading.Thread(target=self._bg_task_func,
446-
daemon=True)
445+
self._bg_task = threading.Thread(target=self._bg_task_func)
447446
self._bg_task.start()
448447

449448
def _bg_task_func(self):
@@ -459,6 +458,9 @@ cdef class ThinPoolImpl(BaseThinPoolImpl):
459458
list conn_impls_to_drop
460459
bint wait
461460

461+
# add to the list of pools that require closing
462+
pools_to_close.add(self)
463+
462464
# create connections and close connections as needed
463465
while True:
464466
conn_impls_to_drop = []
@@ -499,6 +501,9 @@ cdef class ThinPoolImpl(BaseThinPoolImpl):
499501
with self._bg_task_condition:
500502
self._bg_task_condition.wait()
501503

504+
# remove from the list of pools that require closing
505+
pools_to_close.remove(self)
506+
502507
cdef ThinConnImpl _create_conn_impl(self, ConnectParamsImpl params=None):
503508
"""
504509
Create a single connection using the pool's information. This
@@ -638,11 +643,14 @@ cdef class ThinPoolImpl(BaseThinPoolImpl):
638643

639644
def close(self, bint force):
640645
"""
641-
Internal method for closing the pool.
646+
Internal method for closing the pool. Note that the thread to destroy
647+
pools gracefully may have already run, so if the close has already
648+
happened, nothing more needs to be done!
642649
"""
643-
with self._condition:
644-
self._close_helper(force)
645-
self._bg_task.join()
650+
if self in pools_to_close:
651+
with self._condition:
652+
self._close_helper(force)
653+
self._bg_task.join()
646654

647655
def drop(self, ThinConnImpl conn_impl):
648656
"""
@@ -883,3 +891,13 @@ cdef class AsyncThinPoolImpl(BaseThinPoolImpl):
883891
self._busy_conn_impls.remove(conn_impl)
884892
self._drop_conn_impl(conn_impl)
885893
self._condition.notify()
894+
895+
# keep track of which pools need to be closed and ensure that they are closed
896+
# gracefully when the main thread finishes its work
897+
pools_to_close = set()
898+
def close_pools_gracefully():
899+
cdef ThinPoolImpl pool_impl
900+
threading.main_thread().join() # wait for main thread to finish
901+
for pool_impl in list(pools_to_close):
902+
pool_impl.close(True)
903+
threading.Thread(target=close_pools_gracefully).start()

0 commit comments

Comments
 (0)