|
2 | 2 |
|
3 | 3 | ## Summary |
4 | 4 |
|
5 | | -<!-- Here goes a general summary of what this release is about --> |
| 5 | +This release replaces the `@actor` decorator with a new `Actor` class. |
6 | 6 |
|
7 | 7 | ## Upgrading |
8 | 8 |
|
| 9 | + |
9 | 10 | - The `frequenz.sdk.power` package contained the power distribution algorithm, which is for internal use in the sdk, and is no longer part of the public API. |
10 | 11 |
|
11 | 12 | - `PowerDistributingActor`'s result type `OutOfBound` has been renamed to `OutOfBounds`, and its member variable `bound` has been renamed to `bounds`. |
12 | 13 |
|
| 14 | +- The `@actor` decorator was replaced by the new `Actor` class. The main differences between the new class and the old decorator are: |
| 15 | + |
| 16 | + * It doesn't start automatically, `start()` needs to be called to start an actor (using the `frequenz.sdk.actor.run()` function is recommended). |
| 17 | + * The method to implement the main logic was renamed from `run()` to `_run()`, as it is not intended to be run externally. |
| 18 | + * Actors can have an optional `name` (useful for debugging/logging purposes). |
| 19 | + * The actor will only be restarted if an unhandled `Exception` is raised by `_run()`. It will not be restarted if the `_run()` method finishes normally. If an unhandled `BaseException` is raised instead, it will be re-raised. For normal cancellation the `_run()` method should handle `asyncio.CancelledError` if the cancellation shouldn't be propagated (this is the same as with the decorator). |
| 20 | + * The `_stop()` method is public (`stop()`) and will `cancel()` and `await` for the task to finish, catching the `asyncio.CancelledError`. |
| 21 | + * The `join()` method is renamed to `wait()`, but they can also be awaited directly ( `await actor`). |
| 22 | + * For deterministic cleanup, actors can now be used as `async` context managers. |
| 23 | + |
| 24 | + Most actors can be migrated following these steps: |
| 25 | + |
| 26 | + 1. Remove the decorator |
| 27 | + 2. Add `Actor` as a base class |
| 28 | + 3. Rename `run()` to `_run()` |
| 29 | + 4. Forward the `name` argument (optional but recommended) |
| 30 | + |
| 31 | + For example, this old actor: |
| 32 | + |
| 33 | + ```python |
| 34 | + from frequenz.sdk.actor import actor |
| 35 | + |
| 36 | + @actor |
| 37 | + class TheActor: |
| 38 | + def __init__(self, actor_args) -> None: |
| 39 | + # init code |
| 40 | + |
| 41 | + def run(self) -> None: |
| 42 | + # run code |
| 43 | + ``` |
| 44 | + |
| 45 | + Can be migrated as: |
| 46 | + |
| 47 | + ```python |
| 48 | + import asyncio |
| 49 | + from frequenz.sdk.actor import Actor |
| 50 | + |
| 51 | + class TheActor(Actor): |
| 52 | + def __init__(self, actor_args, |
| 53 | + *, |
| 54 | + name: str | None = None, |
| 55 | + ) -> None: |
| 56 | + super().__init__(name=name) |
| 57 | + # init code |
| 58 | + |
| 59 | + def _run(self) -> None: |
| 60 | + # run code |
| 61 | + ``` |
| 62 | + |
| 63 | + Then you can instantiate all your actors first and then run them using: |
| 64 | + |
| 65 | + ```python |
| 66 | + from frequenz.sdk.actor import run |
| 67 | + # Init code |
| 68 | + actor = TheActor() |
| 69 | + other_actor = OtherActor() |
| 70 | + # more setup |
| 71 | + await run(actor, other_actor) # Start and await for all the actors |
| 72 | + ``` |
| 73 | + |
| 74 | +- The `MovingWindow` is now a `BackgroundService`, so it needs to be started manually with `await window.start()`. It is recommended to use it as an `async` context manager if possible though: |
| 75 | + |
| 76 | + ```python |
| 77 | + async with MovingWindow(...) as window: |
| 78 | + # The moving windows is started here |
| 79 | + use(window) |
| 80 | + # The moving window is stopped here |
| 81 | + ``` |
| 82 | + |
| 83 | +- The base actors (`ConfigManagingActor`, `ComponentMetricsResamplingActor`, `DataSourcingActor`, `PowerDistributingActor`) now inherit from the new `Actor` class, if you are using them directly, you need to start them manually with `await actor.start()` and you might need to do some other adjustments. |
| 84 | + |
13 | 85 | ## New Features |
14 | 86 |
|
15 | 87 | - DFS for compentent graph |
16 | 88 |
|
| 89 | +- `BackgroundService`: This new abstract base class can be used to write other classes that runs one or more tasks in the background. It provides a consistent API to start and stop these services and also takes care of the handling of the background tasks. It can also work as an `async` context manager, giving the service a deterministic lifetime and guaranteed cleanup. |
| 90 | + |
| 91 | + All classes spawning tasks that are expected to run for an indeterminate amount of time are likely good candidates to use this as a base class. |
| 92 | + |
| 93 | +- `Actor`: This new class inherits from `BackgroundService` and it replaces the `@actor` decorator. |
| 94 | + |
17 | 95 | ## Bug Fixes |
18 | 96 |
|
19 | 97 | - Fixes a bug in the ring buffer updating the end timestamp of gaps when they are outdated. |
|
0 commit comments