The poll loop remembered what it read rather than what it published, so a value the node could not publish counted as said: the next poll skipped it, succeeded, and health went back to ok with the port still dark. Remember it only after inject returns, and report ok last. A node reporting itself down is now derived into its flow's issues on read and counted on the health summary, so the canvas marks it and Home says so. Being down does not stop the flow, and the issue clears by itself when the node reports well again. The repeating poll warning is logged once per outage rather than once per tick. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K1moruzue2kTJd3uVisgNk
43 lines
1.3 KiB
Python
43 lines
1.3 KiB
Python
"""A node that loaded but is not working shows up as an issue on its flow.
|
|
|
|
Health used to go nowhere: the connector reported it, the controller stored it,
|
|
and no screen ever asked. These cover the derivation that closes that gap.
|
|
"""
|
|
|
|
from pathlib import Path
|
|
|
|
from fluksio.flow.controller import FlowController, LoadedNode
|
|
from fluksio.flow.store import FlowStore
|
|
|
|
|
|
def a_controller(tmp_path: Path) -> FlowController:
|
|
controller = FlowController(FlowStore(tmp_path / "flows"))
|
|
controller.loaded["house.owm"] = LoadedNode(
|
|
id="house.owm",
|
|
flow="house",
|
|
health="down",
|
|
health_detail="ConnectionError: name resolution failed",
|
|
)
|
|
return controller
|
|
|
|
|
|
def test_a_down_node_is_an_issue_on_its_flow(tmp_path: Path) -> None:
|
|
controller = a_controller(tmp_path)
|
|
|
|
issues = controller.flow_issues("house")
|
|
|
|
assert [issue.code for issue in issues] == ["node_unhealthy"]
|
|
assert issues[0].node == "house.owm"
|
|
assert "name resolution failed" in issues[0].message
|
|
# Not advisory: the canvas has to mark the node.
|
|
assert not issues[0].advisory
|
|
assert controller.flow_issues("other") == []
|
|
|
|
|
|
def test_the_issue_clears_when_the_node_reports_itself_well(tmp_path: Path) -> None:
|
|
controller = a_controller(tmp_path)
|
|
|
|
controller.loaded["house.owm"].health = "ok"
|
|
|
|
assert controller.flow_issues("house") == []
|