Do not fail a node because the engine's own stdout is gone
The log tee wrote through to the real stream unguarded, and the worker pool tees a returned call's logs there after reading its result and before handing it back — so a dead stdout, which `fluksio serve` makes possible by running the engine as a child of the dashboard holding that pipe, failed the node with its outputs already in hand. The capture half runs first, so swallowing the write loses nothing. Also: `flow_events` catches the RuntimeError a peer leaving mid-send raises, which is a disconnect by another route, and the remote agent no longer raises out of the task when its subprocess died before it could be written to — the read below reports that and ends the call. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TXQv6KNyyvY7Z1etYTUUAd
This commit is contained in:
@@ -122,6 +122,25 @@ def test_printing_outside_a_node_still_reaches_the_real_stream(capsys):
|
||||
assert "server talking" in capsys.readouterr().out
|
||||
|
||||
|
||||
def test_a_dead_real_stream_does_not_fail_the_node_being_teed():
|
||||
"""`fluksio serve` runs the engine as a child of the dashboard."""
|
||||
|
||||
class Broken:
|
||||
def write(self, text: str) -> int:
|
||||
raise BrokenPipeError(32, "Broken pipe")
|
||||
|
||||
def flush(self) -> None:
|
||||
raise BrokenPipeError(32, "Broken pipe")
|
||||
|
||||
collected: list[str] = []
|
||||
tee = logs._Tee(Broken())
|
||||
with logs.capture(collected.append):
|
||||
assert tee.write("still teed") == len("still teed")
|
||||
tee.flush()
|
||||
|
||||
assert collected == ["still teed"]
|
||||
|
||||
|
||||
def test_installing_twice_does_not_stack_tees():
|
||||
logs.install()
|
||||
once = sys.stdout
|
||||
|
||||
Reference in New Issue
Block a user