|
2 | 2 |
|
3 | 3 | ## Summary |
4 | 4 |
|
5 | | -This release replaces the `@actor` decorator with a new `Actor` class. |
| 5 | +<!-- Here goes a general summary of what this release is about --> |
6 | 6 |
|
7 | 7 | ## Upgrading |
8 | 8 |
|
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. |
11 | | - |
12 | | -- `PowerDistributingActor`'s result type `OutOfBound` has been renamed to `OutOfBounds`, and its member variable `bound` has been renamed to `bounds`. |
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 `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 `actor.start()` and you might need to do some other adjustments. |
84 | | - |
85 | | -- The `BatteryPool.power_distribution_results` method has been enhanced to provide power distribution results in the form of `Power` objects, replacing the previous use of `float` values. |
86 | | - |
87 | | -- In the `Request` class: |
88 | | - * The attribute `request_timeout_sec` has been updated and is now named `request_timeout` and it is represented by a `timedelta` object rather than a `float`. |
89 | | - * The attribute `power` is now presented as a `Power` object, as opposed to a `float`. |
90 | | - |
91 | | -- Within the `EVChargerPool.set_bounds` method, the parameter `max_amps` has been redefined as `max_current`, and it is now represented using a `Current` object instead of a `float`. |
92 | | - |
93 | | -- The argument `nones_are_zeros` in `FormulaEngine` and related classes and methods is now a keyword-only argument. |
| 9 | +<!-- Here goes notes on how to upgrade from previous versions, including deprecations and what they should be replaced with --> |
94 | 10 |
|
95 | 11 | ## New Features |
96 | 12 |
|
97 | | -- Added `DFS` to the component graph |
98 | | - |
99 | | -- `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. |
100 | | - |
101 | | - 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. |
102 | | - |
103 | | -- `Actor`: This new class inherits from `BackgroundService` and it replaces the `@actor` decorator. |
104 | | - |
105 | | -- Newly added `min` and `max` functions for Formulas. They can be used as follows: |
106 | | - |
107 | | - ```python |
108 | | - formula1.min(formula2) |
109 | | - ``` |
| 13 | +<!-- Here goes the main new features and examples or instructions on how to use them --> |
110 | 14 |
|
111 | 15 | ## Bug Fixes |
112 | 16 |
|
113 | | -- Fixes a bug in the ring buffer updating the end timestamp of gaps when they are outdated. |
114 | | - |
115 | | -- Properly handles PV configurations with no or only some meters before the PV component. |
116 | | - |
117 | | - So far we only had configurations like this: `Meter -> Inverter -> PV`. However the scenario with `Inverter -> PV` is also possible and now handled correctly. |
118 | | - |
119 | | -- Fix `consumer_power()` not working certain configurations. |
120 | | - |
121 | | - In microgrids without consumers and no main meter, the formula would never return any values. |
122 | | - |
123 | | -- Fix `pv_power` not working in setups with 2 grid meters by using a new reliable function to search for components in the components graph |
124 | | - |
125 | | -- Fix `consumer_power` and `producer_power` similar to `pv_power` |
126 | | - |
127 | | -- Zero value requests received by the `PowerDistributingActor` will now always be accepted, even when there are non-zero exclusion bounds. |
128 | | - |
129 | | -- Hold on to a reference to all streaming tasks in the microgrid API client, so they don't get garbage collected. |
| 17 | +<!-- Here goes notable bug fixes that are worth a special mention or explanation --> |
0 commit comments