Skip to content

Commit 08673d3

Browse files
committed
util: cleanup asyncio event loop after stopping
I noticed many ResourceWarning when running regtests with PYTHONASYNCIODEBUG=1 and PYTHONDEVMODE=1, each time a daemon gets stopped the asyncio loop wouldn't get properly cleaned up: ``` (env) user@hp:~/code/electrum-fork$ python3 -m unittest tests.regtest.TestLightningAB.test_lnwatcher_waits_until_fees_go_down ***** test_lnwatcher_waits_until_fees_go_down ****** initializing alice 0.67 | W | asyncio | Executing <Task finished name='Task-1' coro=<run_offline_command() done, defined at /home/user/code/electrum-fork/./run_electrum:229> result={'msg': 'Please keep ... your wallet.', 'path': '/tmp/alice/r...efault_wallet', 'seed': 'fiction sadd...it radar desk'} created at /home/user/code/electrum-fork/electrum/util.py:1760> took 0.280 seconds /usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True> /usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True> /usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True> /usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True> /usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True> /usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True> funding alice /usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True> f84277454a04243e500cf84c67aad16e04dd7a88ffa849ffcf20ce3f9af277df /usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True> /usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True> initializing bob 0.54 | W | asyncio | Executing <Task finished name='Task-1' coro=<run_offline_command() done, defined at /home/user/code/electrum-fork/./run_electrum:229> result={'msg': 'Please keep ... your wallet.', 'path': '/tmp/bob/reg...efault_wallet', 'seed': 'wink loud so...ory myth case'} created at /home/user/code/electrum-fork/electrum/util.py:1760> took 0.195 seconds /usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True> /usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True> /usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True> /usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True> /usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True> /usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True> funding bob /usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True> f68b651e84dc8547f54dd09129018a2d0d256dedc8ccc48595ae172de895371a /usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True> mining 1 blocks starting daemon (PID 38153) /usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True> /tmp/alice/regtest/wallets/default_wallet /usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True> ``` This commits adds some cleanup to `util.create_and_start_event_loop()` to 1. cancel remaining tasks 2. shut down asyncgens 3. shutdown the default executor 4. call loop.close() to free the resources allocated to the loop See https://stackoverflow.com/questions/30765606/whats-the-correct-way-to-clean-up-after-an-interrupted-event-loop This seems to reliably solve the mentioned `ResourceWarning`.
1 parent 6423323 commit 08673d3

File tree

1 file changed

+13
-1
lines changed

1 file changed

+13
-1
lines changed

electrum/util.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
from functools import partial
5353
from abc import abstractmethod, ABC
5454
import enum
55-
from contextlib import nullcontext
55+
from contextlib import nullcontext, suppress
5656
import traceback
5757
import inspect
5858

@@ -1704,8 +1704,20 @@ def run_event_loop():
17041704
loop.run_until_complete(stopping_fut)
17051705
finally:
17061706
# clean-up
1707+
try:
1708+
pending_tasks = asyncio.gather(*asyncio.all_tasks(loop), return_exceptions=True)
1709+
pending_tasks.cancel()
1710+
with suppress(asyncio.CancelledError):
1711+
loop.run_until_complete(pending_tasks)
1712+
loop.run_until_complete(loop.shutdown_asyncgens())
1713+
if isinstance(loop, asyncio.BaseEventLoop):
1714+
loop.run_until_complete(loop.shutdown_default_executor())
1715+
except Exception as e:
1716+
_logger.debug(f"exception when cleaning up asyncio event loop: {e}")
1717+
17071718
global _asyncio_event_loop
17081719
_asyncio_event_loop = None
1720+
loop.close()
17091721

17101722
loop.set_exception_handler(on_exception)
17111723
_set_custom_task_factory(loop)

0 commit comments

Comments
 (0)