Skip to content

Commit 547720d

Browse files
committed
Ensure dynamically built 3-phase formula engines aren't cleaned up
This hack was already present for the single-phase formula engine, but we had missed the 3-phase formula engines earlier. Signed-off-by: Sahas Subramanian <[email protected]>
1 parent 2ddcd57 commit 547720d

File tree

1 file changed

+13
-1
lines changed

1 file changed

+13
-1
lines changed

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,19 @@ def new_receiver(
644644
if self._task is None:
645645
self._task = asyncio.create_task(self._run())
646646

647-
return self._channel.new_receiver(name=name, limit=max_size)
647+
recv = self._channel.new_receiver(name=name, limit=max_size)
648+
649+
# This is a hack to ensure that the lifetime of the engine is tied to the
650+
# lifetime of the receiver. This is necessary because the engine is a task that
651+
# runs forever, and in cases where higher order built for example with the below
652+
# idiom, the user would hold no references to the engine and it could get
653+
# garbage collected before the receiver. This behaviour is explained in the
654+
# `asyncio.create_task` docs here:
655+
# https://docs.python.org/3/library/asyncio-task.html#asyncio.create_task
656+
#
657+
# formula = (grid_power_engine + bat_power_engine).build().new_receiver()
658+
recv._engine_reference = self # type: ignore # pylint: disable=protected-access
659+
return recv
648660

649661

650662
class FormulaBuilder(Generic[QuantityT]):

0 commit comments

Comments
 (0)