Skip to content

Commit 71b5fc5

Browse files
committed
Rename BackgroundService to Service
The name `BackgroundService` is a bit too verbose now in the context of an asyncio library. Services are usually already understood as running in the background, so the `Background` prefix is redundant and makes the class name too long. Signed-off-by: Leandro Lucarella <[email protected]>
1 parent d200e54 commit 71b5fc5

File tree

2 files changed

+45
-45
lines changed

2 files changed

+45
-45
lines changed

src/frequenz/core/asyncio.py

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
1111
- [cancel_and_await][frequenz.core.asyncio.cancel_and_await]: A function that cancels a
1212
task and waits for it to finish, handling `CancelledError` exceptions.
13-
- [BackgroundService][frequenz.core.asyncio.BackgroundService]: A base class for
14-
implementing background services that can be started and stopped.
13+
- [Service][frequenz.core.asyncio.Service]: A base class for
14+
implementing services running in the background that can be started and stopped.
1515
"""
1616

1717

@@ -41,38 +41,38 @@ async def cancel_and_await(task: asyncio.Task[Any]) -> None:
4141
pass
4242

4343

44-
class BackgroundService(abc.ABC):
45-
"""A background service that can be started and stopped.
44+
class Service(abc.ABC):
45+
"""A service running in the background.
4646
47-
A background service is a service that runs in the background spawning one or more
48-
tasks. The service can be [started][frequenz.core.asyncio.BackgroundService.start]
49-
and [stopped][frequenz.core.asyncio.BackgroundService.stop] and can work as an
50-
async context manager to provide deterministic cleanup.
47+
A service swpawns one of more background tasks and can be
48+
[started][frequenz.core.asyncio.Service.start] and
49+
[stopped][frequenz.core.asyncio.Service.stop] and can work as an async context
50+
manager to provide deterministic cleanup.
5151
52-
To implement a background service, subclasses must implement the
53-
[`start()`][frequenz.core.asyncio.BackgroundService.start] method, which should
54-
start the background tasks needed by the service, and add them to the `_tasks`
55-
protected attribute.
52+
To implement a service, subclasses must implement the
53+
[`start()`][frequenz.core.asyncio.Service.start] method, which should start the
54+
background tasks needed by the service, and add them to the `_tasks` protected
55+
attribute.
5656
5757
If you need to collect results or handle exceptions of the tasks when stopping the
5858
service, then you need to also override the
59-
[`stop()`][frequenz.core.asyncio.BackgroundService.stop] method, as the base
59+
[`stop()`][frequenz.core.asyncio.Service.stop] method, as the base
6060
implementation does not collect any results and re-raises all exceptions.
6161
6262
!!! warning
6363
64-
As background services manage [`asyncio.Task`][] objects, a reference to them
65-
must be held for as long as the background service is expected to be running,
66-
otherwise its tasks will be cancelled and the service will stop. For more
67-
information, please refer to the [Python `asyncio`
64+
As services manage [`asyncio.Task`][] objects, a reference to them must be held
65+
for as long as the service is expected to be running, otherwise its tasks will
66+
be cancelled and the service will stop. For more information, please refer to
67+
the [Python `asyncio`
6868
documentation](https://docs.python.org/3/library/asyncio-task.html#asyncio.create_task).
6969
7070
Example:
7171
```python
7272
import datetime
7373
import asyncio
7474
75-
class Clock(BackgroundService):
75+
class Clock(Service):
7676
def __init__(self, resolution_s: float, *, unique_id: str | None = None) -> None:
7777
super().__init__(unique_id=unique_id)
7878
self._resolution_s = resolution_s
@@ -101,13 +101,13 @@ async def main() -> None:
101101
"""
102102

103103
def __init__(self, *, unique_id: str | None = None) -> None:
104-
"""Initialize this BackgroundService.
104+
"""Initialize this Service.
105105
106106
Args:
107-
unique_id: The string to uniquely identify this background service instance.
107+
unique_id: The string to uniquely identify this service instance.
108108
If `None`, a string based on `hex(id(self))` will be used. This is
109109
used in `__repr__` and `__str__` methods, mainly for debugging
110-
purposes, to identify a particular instance of a background service.
110+
purposes, to identify a particular instance of a service.
111111
"""
112112
# [2:] is used to remove the '0x' prefix from the hex representation of the id,
113113
# as it doesn't add any uniqueness to the string.
@@ -116,16 +116,16 @@ def __init__(self, *, unique_id: str | None = None) -> None:
116116

117117
@abc.abstractmethod
118118
def start(self) -> None:
119-
"""Start this background service."""
119+
"""Start this service."""
120120

121121
@property
122122
def unique_id(self) -> str:
123-
"""The unique ID of this background service."""
123+
"""The unique ID of this service."""
124124
return self._unique_id
125125

126126
@property
127127
def tasks(self) -> collections.abc.Set[asyncio.Task[Any]]:
128-
"""The set of running tasks spawned by this background service.
128+
"""The set of running tasks spawned by this service.
129129
130130
Users typically should not modify the tasks in the returned set and only use
131131
them for informational purposes.
@@ -139,14 +139,14 @@ def tasks(self) -> collections.abc.Set[asyncio.Task[Any]]:
139139

140140
@property
141141
def is_running(self) -> bool:
142-
"""Whether this background service is running.
142+
"""Whether this service is running.
143143
144144
A service is considered running when at least one task is running.
145145
"""
146146
return any(not task.done() for task in self._tasks)
147147

148148
def cancel(self, msg: str | None = None) -> None:
149-
"""Cancel all running tasks spawned by this background service.
149+
"""Cancel all running tasks spawned by this service.
150150
151151
Args:
152152
msg: The message to be passed to the tasks being cancelled.
@@ -155,7 +155,7 @@ def cancel(self, msg: str | None = None) -> None:
155155
task.cancel(msg)
156156

157157
async def stop(self, msg: str | None = None) -> None:
158-
"""Stop this background service.
158+
"""Stop this service.
159159
160160
This method cancels all running tasks spawned by this service and waits for them
161161
to finish.
@@ -184,10 +184,10 @@ async def stop(self, msg: str | None = None) -> None:
184184
async def __aenter__(self) -> Self:
185185
"""Enter an async context.
186186
187-
Start this background service.
187+
Start this service.
188188
189189
Returns:
190-
This background service.
190+
This service.
191191
"""
192192
self.start()
193193
return self
@@ -200,7 +200,7 @@ async def __aexit__(
200200
) -> None:
201201
"""Exit an async context.
202202
203-
Stop this background service.
203+
Stop this service.
204204
205205
Args:
206206
exc_type: The type of the exception raised, if any.
@@ -210,9 +210,9 @@ async def __aexit__(
210210
await self.stop()
211211

212212
async def wait(self) -> None:
213-
"""Wait this background service to finish.
213+
"""Wait for this service to finish.
214214
215-
Wait until all background service tasks are finished.
215+
Wait until all the service tasks are finished.
216216
217217
Raises:
218218
BaseExceptionGroup: If any of the tasks spawned by this service raised an
@@ -239,13 +239,13 @@ async def wait(self) -> None:
239239
exceptions.append(error)
240240
if exceptions:
241241
raise BaseExceptionGroup(
242-
f"Error while stopping background service {self}", exceptions
242+
f"Error while stopping service {self}", exceptions
243243
)
244244

245245
def __await__(self) -> collections.abc.Generator[None, None, None]:
246-
"""Await this background service.
246+
"""Await this service.
247247
248-
An awaited background service will wait for all its tasks to finish.
248+
An awaited service will wait for all its tasks to finish.
249249
250250
Returns:
251251
An implementation-specific generator for the awaitable.
@@ -255,7 +255,7 @@ def __await__(self) -> collections.abc.Generator[None, None, None]:
255255
def __del__(self) -> None:
256256
"""Destroy this instance.
257257
258-
Cancel all running tasks spawned by this background service.
258+
Cancel all running tasks spawned by this service.
259259
"""
260260
self.cancel("{self!r} was deleted")
261261

tests/test_asyncio.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import async_solipsism
1010
import pytest
1111

12-
from frequenz.core.asyncio import BackgroundService
12+
from frequenz.core.asyncio import Service
1313

1414

1515
# This method replaces the event loop for all tests in the file.
@@ -19,8 +19,8 @@ def event_loop_policy() -> async_solipsism.EventLoopPolicy:
1919
return async_solipsism.EventLoopPolicy()
2020

2121

22-
class FakeService(BackgroundService):
23-
"""A background service that does nothing."""
22+
class FakeService(Service):
23+
"""A service that does nothing."""
2424

2525
def __init__(
2626
self,
@@ -47,7 +47,7 @@ async def nop() -> None:
4747

4848

4949
async def test_construction_defaults() -> None:
50-
"""Test the construction of a background service with default arguments."""
50+
"""Test the construction of a service with default arguments."""
5151
fake_service = FakeService()
5252
assert fake_service.unique_id == hex(id(fake_service))[2:]
5353
assert fake_service.tasks == set()
@@ -60,15 +60,15 @@ async def test_construction_defaults() -> None:
6060

6161

6262
async def test_construction_custom() -> None:
63-
"""Test the construction of a background service with a custom unique ID."""
63+
"""Test the construction of a service with a custom unique ID."""
6464
fake_service = FakeService(unique_id="test")
6565
assert fake_service.unique_id == "test"
6666
assert fake_service.tasks == set()
6767
assert fake_service.is_running is False
6868

6969

7070
async def test_start_await() -> None:
71-
"""Test a background service starts and can be awaited."""
71+
"""Test a service starts and can be awaited."""
7272
fake_service = FakeService(unique_id="test")
7373
assert fake_service.unique_id == "test"
7474
assert fake_service.is_running is False
@@ -88,7 +88,7 @@ async def test_start_await() -> None:
8888

8989

9090
async def test_start_stop() -> None:
91-
"""Test a background service starts and stops correctly."""
91+
"""Test a service starts and stops correctly."""
9292
fake_service = FakeService(unique_id="test", sleep=2.0)
9393
assert fake_service.unique_id == "test"
9494
assert fake_service.is_running is False
@@ -114,7 +114,7 @@ async def test_start_stop() -> None:
114114
async def test_start_and_crash(
115115
method: Literal["await"] | Literal["wait"] | Literal["stop"],
116116
) -> None:
117-
"""Test a background service reports when crashing."""
117+
"""Test a service reports when crashing."""
118118
exc = RuntimeError("error")
119119
fake_service = FakeService(unique_id="test", exc=exc)
120120
assert fake_service.unique_id == "test"
@@ -143,7 +143,7 @@ async def test_start_and_crash(
143143

144144

145145
async def test_async_context_manager() -> None:
146-
"""Test a background service works as an async context manager."""
146+
"""Test a service works as an async context manager."""
147147
async with FakeService(unique_id="test", sleep=1.0) as fake_service:
148148
assert fake_service.is_running is True
149149
# Is a no-op if the service is running

0 commit comments

Comments
 (0)