fix: use event instead of chained timer for daemon

Old solution causes amount of thread to be growing as well as stack is
increased during each iteration. Instead of cycle-free implementation,
this commit just uses while cycle
This commit is contained in:
Evgenii Alekseev 2023-11-30 13:40:59 +02:00
parent aef3cb95bc
commit a689448854
2 changed files with 23 additions and 9 deletions

View File

@ -43,8 +43,10 @@ class Daemon(Handler):
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
""" """
from ahriman.application.handlers import Update from ahriman.application.handlers import Update
event = threading.Event()
try:
while not event.wait(args.interval):
Update.run(args, repository_id, configuration, report=report) Update.run(args, repository_id, configuration, report=report)
timer = threading.Timer(args.interval, Daemon.run, args=[args, repository_id, configuration], except KeyboardInterrupt:
kwargs={"report": report}) pass # normal exit
timer.start()
timer.join()

View File

@ -1,6 +1,7 @@
import argparse import argparse
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from unittest.mock import call as MockCall
from ahriman.application.handlers import Daemon from ahriman.application.handlers import Daemon
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
@ -30,11 +31,22 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
""" """
args = _default_args(args) args = _default_args(args)
run_mock = mocker.patch("ahriman.application.handlers.Update.run") run_mock = mocker.patch("ahriman.application.handlers.Update.run")
start_mock = mocker.patch("threading.Timer.start") wait_mock = mocker.patch("threading.Event.wait", side_effect=[False, True])
join_mock = mocker.patch("threading.Timer.join")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Daemon.run(args, repository_id, configuration, report=True) Daemon.run(args, repository_id, configuration, report=True)
run_mock.assert_called_once_with(args, repository_id, configuration, report=True) run_mock.assert_called_once_with(args, repository_id, configuration, report=True)
start_mock.assert_called_once_with() wait_mock.assert_has_calls([MockCall(args.interval), MockCall(args.interval)])
join_mock.assert_called_once_with()
def test_run_keyboard_interrupt(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
"""
must handle KeyboardInterrupt exception
"""
args = _default_args(args)
mocker.patch("ahriman.application.handlers.Update.run", side_effect=KeyboardInterrupt)
wait_mock = mocker.patch("threading.Event.wait", return_value=False)
_, repository_id = configuration.check_loaded()
Daemon.run(args, repository_id, configuration, report=True)
wait_mock.assert_called_once_with(args.interval)