renames restart_on_failure to restart_on_exception

This commit is contained in:
Mose Müller 2025-01-18 07:19:04 +01:00
parent 3a67c07bad
commit b24db00eda
4 changed files with 24 additions and 31 deletions

View File

@ -44,11 +44,11 @@ The [`@task`][pydase.task.decorator.task] decorator replaces the function with a
The [`@task`][pydase.task.decorator.task] decorator supports several options inspired by systemd unit services, allowing fine-grained control over task behavior:
- **`autostart`**: Automatically starts the task when the service initializes. Defaults to `False`.
- **`restart_on_failure`**: Configures whether the task should restart if it exits due to an exception (other than `asyncio.CancelledError`). Defaults to `True`.
- **`restart_on_exception`**: Configures whether the task should restart if it exits due to an exception (other than `asyncio.CancelledError`). Defaults to `True`.
- **`restart_sec`**: Specifies the delay (in seconds) before restarting a failed task. Defaults to `1.0`.
- **`start_limit_interval_sec`**: Configures a time window (in seconds) for rate limiting task restarts. If the task restarts more than `start_limit_burst` times within this interval, it will no longer restart. Defaults to `None` (disabled).
- **`start_limit_burst`**: Defines the maximum number of restarts allowed within the interval specified by `start_limit_interval_sec`. Defaults to `3`.
- **`exit_on_failure`**: If set to `True`, the service will exit if the task fails and either `restart_on_failure` is `False` or the start rate limiting is exceeded. Defaults to `False`.
- **`exit_on_failure`**: If set to `True`, the service will exit if the task fails and either `restart_on_exception` is `False` or the start rate limiting is exceeded. Defaults to `False`.
### Example with Advanced Options
@ -65,7 +65,7 @@ class AdvancedTaskService(pydase.DataService):
@task(
autostart=True,
restart_on_failure=True,
restart_on_exception=True,
restart_sec=2.0,
start_limit_interval_sec=10.0,
start_limit_burst=5,
@ -80,10 +80,3 @@ if __name__ == "__main__":
service = AdvancedTaskService()
pydase.Server(service=service).run()
```
## Key Points
1. **Restart Behavior**: Tasks configured with `restart_on_failure=True` will restart after a failure, subject to the limits specified by `start_limit_interval_sec` and `start_limit_burst`.
2. **Graceful Shutdown**: Tasks that are manually stopped or cancelled will not trigger restarts.
3. **Critical Failures**: If `exit_on_failure=True`, the service will terminate if the task fails irrecoverably.

View File

@ -31,7 +31,7 @@ class PerInstanceTaskDescriptor(Generic[R]):
func: Callable[[Any], Coroutine[None, None, R]]
| Callable[[], Coroutine[None, None, R]],
autostart: bool,
restart_on_failure: bool,
restart_on_exception: bool,
restart_sec: float,
start_limit_interval_sec: float | None,
start_limit_burst: int,
@ -40,7 +40,7 @@ class PerInstanceTaskDescriptor(Generic[R]):
self.__func = func
self.__autostart = autostart
self.__task_instances: dict[object, Task[R]] = {}
self.__restart_on_failure = restart_on_failure
self.__restart_on_exception = restart_on_exception
self.__restart_sec = restart_sec
self.__start_limit_interval_sec = start_limit_interval_sec
self.__start_limit_burst = start_limit_burst
@ -80,7 +80,7 @@ class PerInstanceTaskDescriptor(Generic[R]):
Task(
self.__func.__get__(instance, owner),
autostart=self.__autostart,
restart_on_failure=self.__restart_on_failure,
restart_on_exception=self.__restart_on_exception,
restart_sec=self.__restart_sec,
start_limit_interval_sec=self.__start_limit_interval_sec,
start_limit_burst=self.__start_limit_burst,
@ -94,7 +94,7 @@ class PerInstanceTaskDescriptor(Generic[R]):
def task( # noqa: PLR0913
*,
autostart: bool = False,
restart_on_failure: bool = True,
restart_on_exception: bool = True,
restart_sec: float = 1.0,
start_limit_interval_sec: float | None = None,
start_limit_burst: int = 3,
@ -128,7 +128,7 @@ def task( # noqa: PLR0913
autostart:
If set to True, the task will automatically start when the service is
initialized. Defaults to False.
restart_on_failure:
restart_on_exception:
Configures whether the task shall be restarted when it exits with an
exception other than [`asyncio.CancelledError`][asyncio.CancelledError].
restart_sec:
@ -142,8 +142,8 @@ def task( # noqa: PLR0913
`start_limit_burst` times within an `start_limit_interval_sec` time span are
not permitted to start any more. Defaults to 3.
exit_on_failure:
If True, exit the service if the task fails and restart_on_failure is False
or burst limits are exceeded.
If True, exit the service if the task fails and restart_on_exception is
False or burst limits are exceeded.
Returns:
A decorator that wraps an asynchronous function in a
[`PerInstanceTaskDescriptor`][pydase.task.decorator.PerInstanceTaskDescriptor]
@ -184,7 +184,7 @@ def task( # noqa: PLR0913
return PerInstanceTaskDescriptor(
func,
autostart=autostart,
restart_on_failure=restart_on_failure,
restart_on_exception=restart_on_exception,
restart_sec=restart_sec,
start_limit_interval_sec=start_limit_interval_sec,
start_limit_burst=start_limit_burst,

View File

@ -41,7 +41,7 @@ class Task(pydase.data_service.data_service.DataService, Generic[R]):
autostart:
If set to True, the task will automatically start when the service is
initialized. Defaults to False.
restart_on_failure:
restart_on_exception:
Configures whether the task shall be restarted when it exits with an
exception other than [`asyncio.CancelledError`][asyncio.CancelledError].
restart_sec:
@ -55,8 +55,8 @@ class Task(pydase.data_service.data_service.DataService, Generic[R]):
`start_limit_burst` times within an `start_limit_interval_sec` time span are
not permitted to start any more. Defaults to 3.
exit_on_failure:
If True, exit the service if the task fails and restart_on_failure is False
or burst limits are exceeded.
If True, exit the service if the task fails and restart_on_exception is
False or burst limits are exceeded.
Example:
```python
@ -90,7 +90,7 @@ class Task(pydase.data_service.data_service.DataService, Generic[R]):
func: Callable[[], Coroutine[None, None, R | None]],
*,
autostart: bool,
restart_on_failure: bool,
restart_on_exception: bool,
restart_sec: float,
start_limit_interval_sec: float | None,
start_limit_burst: int,
@ -98,7 +98,7 @@ class Task(pydase.data_service.data_service.DataService, Generic[R]):
) -> None:
super().__init__()
self._autostart = autostart
self._restart_on_failure = restart_on_failure
self._restart_on_exception = restart_on_exception
self._restart_sec = restart_sec
self._start_limit_interval_sec = start_limit_interval_sec
self._start_limit_burst = start_limit_burst
@ -212,7 +212,7 @@ class Task(pydase.data_service.data_service.DataService, Generic[R]):
self, attempts: int, start_time_of_start_limit_interval: float
) -> bool:
"""Determine if the task should be restarted."""
if not self._restart_on_failure:
if not self._restart_on_exception:
return False
if self._start_limit_interval_sec is not None:

View File

@ -292,9 +292,9 @@ async def test_manual_start_with_multiple_service_instances(
@pytest.mark.asyncio(scope="function")
async def test_restart_on_failure(caplog: LogCaptureFixture) -> None:
async def test_restart_on_exception(caplog: LogCaptureFixture) -> None:
class MyService(pydase.DataService):
@task(restart_on_failure=True, restart_sec=0.1)
@task(restart_on_exception=True, restart_sec=0.1)
async def my_task(self) -> None:
logger.info("Triggered task.")
raise Exception("Task failure")
@ -316,7 +316,7 @@ async def test_restart_on_failure(caplog: LogCaptureFixture) -> None:
@pytest.mark.asyncio(scope="function")
async def test_restart_sec(caplog: LogCaptureFixture) -> None:
class MyService(pydase.DataService):
@task(restart_on_failure=True, restart_sec=0.1)
@task(restart_on_exception=True, restart_sec=0.1)
async def my_task(self) -> None:
logger.info("Triggered task.")
raise Exception("Task failure")
@ -341,7 +341,7 @@ async def test_exceeding_start_limit_interval_sec_and_burst(
) -> None:
class MyService(pydase.DataService):
@task(
restart_on_failure=True,
restart_on_exception=True,
restart_sec=0.0,
start_limit_interval_sec=1.0,
start_limit_burst=2,
@ -365,7 +365,7 @@ async def test_non_exceeding_start_limit_interval_sec_and_burst(
) -> None:
class MyService(pydase.DataService):
@task(
restart_on_failure=True,
restart_on_exception=True,
restart_sec=0.1,
start_limit_interval_sec=0.1,
start_limit_burst=2,
@ -388,7 +388,7 @@ async def test_exit_on_failure(
monkeypatch: pytest.MonkeyPatch, caplog: LogCaptureFixture
) -> None:
class MyService(pydase.DataService):
@task(restart_on_failure=False, exit_on_failure=True)
@task(restart_on_exception=False, exit_on_failure=True)
async def my_task(self) -> None:
logger.info("Triggered task.")
raise Exception("Critical failure")
@ -414,7 +414,7 @@ async def test_exit_on_failure_exceeding_rate_limit(
) -> None:
class MyService(pydase.DataService):
@task(
restart_on_failure=True,
restart_on_exception=True,
restart_sec=0.0,
start_limit_interval_sec=0.1,
start_limit_burst=2,