mirror of
https://github.com/tiqi-group/pydase.git
synced 2025-04-21 00:40:01 +02:00
Merge pull request #43 from tiqi-group/42-enhanced-signal-handling-for-asyncio-loop
Enhances signal handling, adds force exit capability
This commit is contained in:
commit
2e9ced4e5e
19
poetry.lock
generated
19
poetry.lock
generated
@ -1536,6 +1536,23 @@ pytest = ">=4.6"
|
||||
[package.extras]
|
||||
testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-mock"
|
||||
version = "3.11.1"
|
||||
description = "Thin-wrapper around the mock package for easier use with pytest"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pytest-mock-3.11.1.tar.gz", hash = "sha256:7f6b125602ac6d743e523ae0bfa71e1a697a2f5534064528c6ff84c2f7c2fc7f"},
|
||||
{file = "pytest_mock-3.11.1-py3-none-any.whl", hash = "sha256:21c279fff83d70763b05f8874cc9cfb3fcacd6d354247a976f9529d19f9acf39"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pytest = ">=5.0"
|
||||
|
||||
[package.extras]
|
||||
dev = ["pre-commit", "pytest-asyncio", "tox"]
|
||||
|
||||
[[package]]
|
||||
name = "python-dateutil"
|
||||
version = "2.8.2"
|
||||
@ -2012,4 +2029,4 @@ h11 = ">=0.9.0,<1"
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.10"
|
||||
content-hash = "409dcbb9f27079667033d1111bdc1ca99436c0e28568562dece75b590aa80e08"
|
||||
content-hash = "b2763b13a2e00c8094a0c30f6157e72c118bab47ab2d9a0357345b33693e6afa"
|
||||
|
@ -35,6 +35,7 @@ flake8-pep604 = "^0.1.0"
|
||||
flake8-eradicate = "^1.4.0"
|
||||
matplotlib = "^3.7.2"
|
||||
pyright = "^1.1.323"
|
||||
pytest-mock = "^3.11.1"
|
||||
|
||||
|
||||
[tool.poetry.group.docs.dependencies]
|
||||
|
@ -358,20 +358,16 @@ class Server:
|
||||
# Signals can only be listened to from the main thread.
|
||||
return
|
||||
|
||||
try:
|
||||
for sig in HANDLED_SIGNALS:
|
||||
self._loop.add_signal_handler(sig, self.handle_exit, sig, None)
|
||||
except NotImplementedError:
|
||||
# Windows
|
||||
for sig in HANDLED_SIGNALS:
|
||||
signal.signal(sig, self.handle_exit)
|
||||
for sig in HANDLED_SIGNALS:
|
||||
signal.signal(sig, self.handle_exit)
|
||||
|
||||
def handle_exit(self, sig: int = 0, frame: Optional[FrameType] = None) -> None:
|
||||
logger.info("Handling exit")
|
||||
if self.should_exit and sig == signal.SIGINT:
|
||||
self.force_exit = True
|
||||
logger.warning(f"Received signal {sig}, forcing exit...")
|
||||
os._exit(1)
|
||||
else:
|
||||
self.should_exit = True
|
||||
logger.warning(f"Received signal {sig}, exiting...")
|
||||
|
||||
def custom_exception_handler(
|
||||
self, loop: asyncio.AbstractEventLoop, context: dict[str, Any]
|
||||
|
35
tests/server/test_server.py
Normal file
35
tests/server/test_server.py
Normal file
@ -0,0 +1,35 @@
|
||||
import signal
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
import pydase
|
||||
|
||||
|
||||
def test_signal_handling(mocker: MockerFixture):
|
||||
# Mock os._exit and signal.signal
|
||||
mock_exit = mocker.patch("os._exit")
|
||||
mock_signal = mocker.patch("signal.signal")
|
||||
|
||||
class MyService(pydase.DataService):
|
||||
pass
|
||||
|
||||
# Instantiate your server object
|
||||
server = pydase.Server(MyService())
|
||||
|
||||
# Call the method to install signal handlers
|
||||
server.install_signal_handlers()
|
||||
|
||||
# Check if the signal handlers were registered correctly
|
||||
assert mock_signal.call_args_list == [
|
||||
mocker.call(signal.SIGINT, server.handle_exit),
|
||||
mocker.call(signal.SIGTERM, server.handle_exit),
|
||||
]
|
||||
|
||||
# Simulate receiving a SIGINT signal for the first time
|
||||
server.handle_exit(signal.SIGINT, None)
|
||||
assert server.should_exit # assuming should_exit is public
|
||||
mock_exit.assert_not_called()
|
||||
|
||||
# Simulate receiving a SIGINT signal for the second time
|
||||
server.handle_exit(signal.SIGINT, None)
|
||||
mock_exit.assert_called_once_with(1)
|
Loading…
x
Reference in New Issue
Block a user