| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
… if labels are modified in ui
|
The version of this update should be: 0.0.1-alpha. |
Sorry, something went wrong.
Completes the item-StreamController#1 pattern (issue StreamController#55) in the sibling method: the loop re-read controller.active_page per check, so a non-None guard could race a concurrent (dis)connect clearing it and then deref None.json_path. Snapshot it once, mirroring update_input/update_key_image (item StreamController#8). _pages_lock is the wrong tool here -- it guards self.pages, not active_page writes. Also document that _save_locks grows one entry per page path and is never pruned (bounded by page count; no eviction machinery warranted). Extends scenario_reload_similar_pages with a flip-to-None probe (red-checked: pre-fix raises AttributeError on .json_path).
…longer freezes the deck (StreamController#1) The writer thread (sole path for paints/brightness/Clear/ClearAndClose since the single-writer migration) ran unguarded: any uncaught exception killed it, freezing the deck until replug while control_q grew unbounded. run() now delegates to _run_one_tick() inside a guarded loop: a tick exception is logged with full traceback (rate-limited to 1/5s with a suppressed-repeat count -- local limiter until StreamController#91), _stop is honored in the except path so a failing body can't strand close(), and a 0.25s wake-event backoff bounds a persistent failure at ~4 retries/s instead of a 100% spin. @log.catch on run() would log once and let the thread die -- the guard must live inside the while. Composes with StreamController#80: the hooks report an escaping death; this prevents the death. The five audit-verified crash vectors are also fixed at the source: (a) init_inputs is build-then-swap and the screensaver drops its `inputs = {}` pre-clear (was an empty-dict window on every screensaver entry); the loop snapshots the dict once per tick and uses .get(); (b) the loop snapshots background.video once (set_video(None) race); (c) touchscreen get_current_image guards a nulled active_page (blank strip); (d) the touchscreen tick gate snapshots state.background_video (_release_background_video race); (e) _exec_clear snapshots the touchscreen slot and nulls it identity-compared -- the crash half of StreamController#1 and this site's half of StreamController#8. tests/scenario_writer_survival.py (first leg of StreamController#61) runs the REAL loop over the stub tier: survives a poisoned tick, resumes paints, caps the log storm, and stop() joins while every tick raises. fixtures gains _QuietInputState (get_active_state) since the live loop path never executed on stubs before (StreamController#69 stub-drift). Suite: 34/34.
…ks, finally'd running flag (StreamController#1 review round 1) Review round 1 on MR !3 confirmed two starvation holes in the new guard plus cheap hardening items; all applied: - Batch recovery [MEDIUM]: a caught tick exception had already popped the tick's image_tasks/touchscreen_task, so the failing frame's siblings were lost with it and nothing scheduled recovery -- after e.g. a TypeError on key 3 of a 15-key repaint, the remaining keys kept the previous page's imagery silently forever. The except path now arms _schedule_full_repaint(); its existing 2s rate limit keeps a deterministic per-tick failure from repaint-storming. - Drain-first ticks [MEDIUM]: check_resume_gap/_run_pending_repaint ran before drain_control_queue inside the same guard, so a persistent pre-drain failure starved SetBrightnessMsg/ClearMsg/ClearAndCloseMsg (deck never blanked/closed on quit) -- and the 'drains first, unconditionally' comment was false. The drain now truly leads the tick; comment updated to cover both orderings. - running=False moved into a finally [LOW]: the guard is except Exception, so an escaping BaseException (SystemExit/KeyboardInterrupt) left running=True and every later stop() burned its full 2s join timeout. - Bounded except-path backoff [LOW]: every producer sets _wake_event, so a single wait(0.25) under a set_media storm returned immediately and the retry rate tracked the producer rate; re-wait until the backoff truly elapsed, only _stop cuts it short. - Reworded the rate-limiter suffix ('N earlier repeats were suppressed') -- the old 'in the last 5s' wording was wrong when the suffix emitted hours after the burst. - Updated the stale 'loop has no exception guard' comment in DeckController.__init__. Tests: scenario_writer_survival gains batch-recovery and control-drain legs mirroring the review's probes; both red-tested against their reverted fixes. Harness 34/34.
fix(deck): guard the sole-writer media loop (StreamController#1) Closes StreamController#1 See merge request naz/StreamController!3
| Back | FazBrowse Home | New Git URL |
First beta version of StreamController. Enjoy it!