Skip to content
This repository was archived by the owner on Oct 28, 2026. It is now read-only.

Roku displays close after multimer's keep-alive loop, not before - #248

Merged
bdbarnett merged 1 commit into
mainfrom
fix/roku-close-245
Oct 27, 2026
Merged

bdbarnett merged 1 commit into
mainfrom
fix/roku-close-245

Conversation

@bdbarnett

Copy link
Copy Markdown
Collaborator

Fixes #245.

A timer-driven app like testris keeps running after its script body ends, kept alive from multimer's exit hook. RokuDisplay and RokuDisplayWrapper registered close() with atexit on their first frame, so it ran before that loop and quit the Companion channel while the app was still drawing. If the first frame came from a timer instead, the hook was registered during exit and never ran, so the channel was never closed.

close() now goes to multimer's stop hooks when multimer is keeping the program alive, and to atexit otherwise. show() returns early while close() runs: a timer could run it inside close()'s blocking ECP request, relaunch the channel and leave _launched set, so the next frame server was never fetched.

Checked:

  • tests/test_roku_close.py is new. Both of its behaviour tests fail on the old code. The re-entrancy one fails with bind, launch, quit, launch, bind, the order the issue describes.
  • A script with timer-driven frames on Linux CPython shows five frames, then the quit and the server closing. Before the fix it never closed.
  • On MicroPython unix, a -c run still closes at exit.
  • testris on Windows CPython against the Roku Companion channel, three 40-second runs: fetched 332, 396 and 199 frames (8.3, 9.9 and 5.0 fps), with no quit during the run. Before the fix, 3 runs in 4 fetched nothing.
  • tests/test_cast_backends.py still passes.

A timer-driven app's script body ends while the app is still running, and
multimer keeps it alive from its own exit hook. RokuDisplay and
RokuDisplayWrapper registered close() with atexit on their first frame, so
close() ran before that loop and quit the channel while the app was still
drawing. When the first frame came from a timer instead, the hook was
registered during exit and never ran at all.

close() now goes to multimer's stop hooks when multimer is keeping the
program alive, and to atexit otherwise. show() also returns early while
close() is running: a timer could run it inside close()'s blocking ECP
request, relaunch the channel and leave _launched set, so the next frame
server was never fetched.

Fixes #245
@bdbarnett
bdbarnett merged commit 7362da3 into main Oct 27, 2026
5 checks passed
@bdbarnett
bdbarnett deleted the fix/roku-close-245 branch October 27, 2026 18:05
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Roku cast: testris on Windows CPython closes its own channel at startup (atexit close runs while the app is still alive)

1 participant