-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
improved handling of abort (ctrl + c) (#349)
* no double mypy in devcontainer removed ms-python extension and using dmypy which checks the whole workspace (specified targets) * HaltUser thrown on AsyncMessageAbort So that scenario stops directly, without waiting for tasks to finish. * let router do the cleanup instead of worker * kill task greenlet when aborting a run better exception logging when something goes wrong in a task. better "request" statistics for SCENARIO. * a test project that can be used to test in grizzly * updates for handling abort (ctrl + c) in async-messaged * update jinja to patch cve-2024-22195 * fixed linting errors * fix pyright zmq type warnings in tests increase timeout for `*no_pymqi*` tests. * handling more error cases during abort * exclude unnecessary stuff when doing local install builds with grizzly-cli * additional handling of error paths when async-messaged is terminated two new messages sent from worker to master: - return_code, the workers return code. the highest reported return code will be used by the master when exiting - sig_trap, message to tell master that a signal has been received and that the test is aborted. this is needed since compose services with healthchecks does not trap signals correctly, which means that `grizzly-cli` wouldn't get correct return code * let router close the integration when closing down * improved logging * correct key for cleaning `client_worker_map` * if there still is sender and/or receivers, change response action to "DISCONNECTING" so that the worker doesn't stop before all entitites has been disconnected * fixed unit tests
- Loading branch information
Showing
39 changed files
with
629 additions
and
334 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
./tests/ | ||
./build/ | ||
./**/*.egg-info | ||
.*/ | ||
!.git |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,3 +31,4 @@ docs/_build* | |
grizzly/__version__.py | ||
.pytest_tmp/ | ||
tests/project | ||
tests/test-project/**/_*.feature |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,60 +1,84 @@ | ||
"""Additional custom gevent functionality.""" | ||
from __future__ import annotations | ||
|
||
from contextlib import contextmanager | ||
from functools import wraps | ||
from typing import Any, Callable | ||
from typing import TYPE_CHECKING, Any, Callable | ||
|
||
from gevent import Greenlet, getcurrent | ||
|
||
if TYPE_CHECKING: | ||
import logging | ||
from collections.abc import Generator | ||
|
||
class GreenletWithExceptionCatching(Greenlet): | ||
|
||
class GreenletFactory: | ||
"""Catch exceptions thrown by a function executing in a greenlet.""" | ||
|
||
started_from: Greenlet | ||
logger: logging.Logger | ||
ignore_exceptions: list[type[Exception]] | ||
index: int | ||
total: int | ||
description: str | ||
|
||
def __init__(self, *args: Any, **kwargs: Any) -> None: | ||
def __init__(self, *args: Any, logger: logging.Logger, ignore_exceptions: list[type[Exception]] | None = None, **kwargs: Any) -> None: | ||
"""Initialize Greenlet object, with custom property from which greenlet this greenlet was started.""" | ||
super().__init__(*args, **kwargs) | ||
self.started_from = getcurrent() | ||
self.logger = logger | ||
self.ignore_exceptions = ignore_exceptions if ignore_exceptions is not None else [] | ||
self.index = -1 | ||
self.total = -1 | ||
self.description = '' | ||
|
||
def handle_exception(self, error: Exception) -> None: | ||
def handle_exception(self, exception: Exception) -> None: | ||
"""Handle exception thrown, by throwing it from the greenlet that started this greenlet.""" | ||
self.started_from.throw(error) | ||
if exception.__class__ not in self.ignore_exceptions and self.total > 0: | ||
message = f'task {self.index} of {self.total} failed: {self.description}' | ||
self.logger.exception(message) | ||
|
||
self.started_from.throw(exception) | ||
|
||
def wrap_exceptions(self, func: Callable) -> Callable: | ||
"""Make sure exceptions is thrown from the correct place, so it can be handled.""" | ||
@wraps(func) | ||
def exception_handler(*args: Any, **kwargs: Any) -> Any: | ||
try: | ||
return func(*args, **kwargs) | ||
result = func(*args, **kwargs) | ||
|
||
if self.total > 0: | ||
message = f'task {self.index} of {self.total} executed: {self.description}' | ||
self.logger.debug(message) | ||
except Exception as exception: | ||
self.wrap_exceptions(self.handle_exception)(exception) | ||
return exception # pragma: no cover | ||
return exception | ||
else: | ||
return result | ||
|
||
return exception_handler | ||
|
||
def spawn(self, func: Callable, *args: Any, **kwargs: Any) -> Greenlet: | ||
"""Spawn a greenlet executing the function, in a way that any exceptions can be handled where it was spawned.""" | ||
return super().spawn( | ||
return Greenlet.spawn( | ||
self.wrap_exceptions(func), | ||
*args, | ||
**kwargs, | ||
) | ||
|
||
def spawn_blocking(self, func: Callable, *args: Any, **kwargs: Any) -> None: | ||
@contextmanager | ||
def spawn_task(self, func: Callable, index: int, total: int, description: str, *args: Any, **kwargs: Any) -> Generator[Greenlet, None, None]: | ||
"""Spawn a greenlet executing the function and wait for the function to finish. | ||
Get the result of the executed function, if there was an exception raised, it will be | ||
re-raised by `get`. | ||
""" | ||
self.index = index | ||
self.total = total | ||
self.description = description | ||
|
||
greenlet = self.spawn(func, *args, **kwargs) | ||
|
||
yield greenlet | ||
|
||
greenlet.join() | ||
greenlet.get() | ||
|
||
def spawn_later(self, seconds: int, func: Callable, *args: Any, **kwargs: Any) -> Greenlet: | ||
"""Spawn a greenlet `seconds` in the future, in a way that any exceptions can be handled where it was spawned.""" | ||
return super().spawn_later( | ||
seconds, | ||
self.wrap_exceptions(func), | ||
*args, | ||
**kwargs, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.