From 383490027b1fabe2cdfdcb1fc5c44acbfd44fd39 Mon Sep 17 00:00:00 2001 From: flemming-it Date: Sat, 18 Jul 2026 17:33:11 +0200 Subject: [PATCH] fix(audit): cancel the live-stream reconnect timer on dispose MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The onDone handler armed an anonymous 3 s reconnect timer that nothing could cancel; when the stream closed right before the page was disposed (no hub, connect ends in onDone instead of onError), the timer outlived the tree. The a11y suite caught this as the rare 'Timer is still pending' flake noted in the night log — the failure reason is now captured and the timer lives in a field that dispose() cancels. Signed-off-by: flemming-it --- lib/pages/audit.dart | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/pages/audit.dart b/lib/pages/audit.dart index ce454a3..d9e7645 100644 --- a/lib/pages/audit.dart +++ b/lib/pages/audit.dart @@ -81,6 +81,7 @@ class _AuditPageState extends State { /// filtering, and the hash-chain ordering exactly as before. StreamSubscription? _eventSub; Timer? _nudgeDebounce; + Timer? _reconnect; @override void initState() { @@ -97,6 +98,7 @@ class _AuditPageState extends State { Workspace.instance.removeListener(_onWorkspaceChanged); _poller?.cancel(); _nudgeDebounce?.cancel(); + _reconnect?.cancel(); _eventSub?.cancel(); super.dispose(); } @@ -122,7 +124,12 @@ class _AuditPageState extends State { onDone: () { _eventSub = null; if (mounted) { - Timer(const Duration(seconds: 3), () { + // Held in a field so dispose() can cancel it — an + // anonymous timer here outlives the page when the + // stream closes right before navigation (the a11y + // suite caught this as a pending-timer flake). + _reconnect?.cancel(); + _reconnect = Timer(const Duration(seconds: 3), () { if (mounted && _eventSub == null) _subscribeLive(); }); }