Skip to content

Commit 9d617fa

Browse files
authored
CI cleanup fixes (#1239)
- **Set min numpy version to lowest prebuilt python3.13-compatible release** - **ComponentTracker: Use run_forever with eventloop fixes for _run() loop** - **Actor: Don't restart on RuntimeError:No Running Eventloop** - **Use get_running_loop() instead of str cmp to check for a running event loop** - **cancel_and_wait: Re-raise if it was our task** - **Fix swallowing of cancel error in Formula Engine & Voltage streamer**
2 parents d118f42 + 988ee5c commit 9d617fa

File tree

6 files changed

+37
-22
lines changed

6 files changed

+37
-22
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ dependencies = [
3434
"frequenz-channels >= 1.6.1, < 2.0.0",
3535
"frequenz-quantities[marshmallow] >= 1.0.0, < 2.0.0",
3636
"networkx >= 2.8, < 4",
37-
"numpy >= 2, < 3",
37+
"numpy >= 2.1.0, < 3",
3838
"typing_extensions >= 4.13.0, < 5",
3939
"marshmallow >= 3.19.0, < 5",
4040
"marshmallow_dataclass >= 8.7.1, < 9",

src/frequenz/sdk/_internal/_asyncio.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import asyncio
88
import logging
9+
import sys
910
from abc import ABC
1011
from datetime import timedelta
1112
from typing import Any, Callable, Coroutine
@@ -22,14 +23,27 @@ async def cancel_and_await(task: asyncio.Task[Any]) -> None:
2223
2324
Args:
2425
task: The task to be cancelled and waited for.
26+
27+
Raises:
28+
asyncio.CancelledError: when our task was cancelled
2529
"""
2630
if task.done():
2731
return
2832
task.cancel()
2933
try:
3034
await task
3135
except asyncio.CancelledError:
32-
pass
36+
if not task.cancelled():
37+
raise
38+
39+
40+
def is_loop_running() -> bool:
41+
"""Check if the event loop is running."""
42+
try:
43+
asyncio.get_running_loop()
44+
return True
45+
except RuntimeError:
46+
return False
3347

3448

3549
async def run_forever(
@@ -46,20 +60,10 @@ async def run_forever(
4660
while True:
4761
try:
4862
await async_callable()
49-
except RuntimeError as exc:
50-
if "no running event loop" in str(exc):
51-
_logger.exception(
52-
"Something went wrong, no running event loop, skipping execution of %s",
53-
async_callable.__name__,
54-
)
55-
return
5663
except Exception: # pylint: disable=broad-except
57-
if not asyncio.get_event_loop().is_running():
58-
_logger.exception(
59-
"Something went wrong, no running event loop, skipping execution of %s",
60-
async_callable.__name__,
61-
)
62-
return
64+
if not is_loop_running():
65+
_logger.exception("There is no running event loop, aborting...")
66+
sys.exit(-1)
6367
_logger.exception("Restarting after exception")
6468
await asyncio.sleep(interval_s)
6569

src/frequenz/sdk/actor/_actor.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import logging
99
from datetime import timedelta
1010

11+
from .._internal._asyncio import is_loop_running
1112
from ._background_service import BackgroundService
1213

1314
_logger = logging.getLogger(__name__)
@@ -105,6 +106,14 @@ async def _run_loop(self) -> None:
105106
_logger.info("Actor %s: Cancelled.", self)
106107
raise
107108
except Exception: # pylint: disable=broad-except
109+
if not is_loop_running():
110+
_logger.exception(
111+
"Something went wrong, no running event loop,"
112+
" not trying to restart %s again.",
113+
self,
114+
)
115+
raise
116+
108117
if self._is_cancelled:
109118
# If actor was cancelled, but any tasks have failed with an exception
110119
# other than asyncio.CancelledError, those exceptions are combined

src/frequenz/sdk/microgrid/_power_distributing/_component_status/_battery_status_tracker.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
)
3737
from typing_extensions import override
3838

39+
from frequenz.sdk._internal._asyncio import run_forever
40+
3941
from ....actor._background_service import BackgroundService
4042
from ... import connection_manager
4143
from ._blocking_status import BlockingStatus
@@ -262,7 +264,7 @@ async def _run(
262264
inverter = inverter_receiver
263265
set_power_result = set_power_result_receiver
264266

265-
while True:
267+
async def _loop() -> None:
266268
try:
267269
async for selected in select(
268270
battery,
@@ -317,6 +319,8 @@ async def _run(
317319
except Exception as err: # pylint: disable=broad-except
318320
_logger.exception("BatteryStatusTracker crashed with error: %s", err)
319321

322+
await run_forever(_loop)
323+
320324
def _get_current_status(self) -> ComponentStatusEnum:
321325
"""Get current battery status.
322326

src/frequenz/sdk/timeseries/_voltage_streamer.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,5 @@ async def _send_request(self) -> None:
190190
"Phase-to-neutral 3-phase voltage streaming task cancelled: %s",
191191
self._source_component,
192192
)
193-
break
194-
else:
195-
await sender.send(msg)
193+
raise
194+
await sender.send(msg)

src/frequenz/sdk/timeseries/formula_engine/_formula_engine.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -584,9 +584,8 @@ async def _run(self) -> None:
584584
)
585585
except asyncio.CancelledError:
586586
_logger.debug("FormulaEngine task cancelled: %s", self._name)
587-
break
588-
else:
589-
await sender.send(msg)
587+
raise
588+
await sender.send(msg)
590589

591590
def new_receiver(
592591
self, name: str | None = None, max_size: int = 50

0 commit comments

Comments
 (0)