fix(test): cancel one-shot Timers on CacheFiller / MutationReplayer dispose
Smoke test failed: "A Timer is still pending even after the widget tree was disposed." Both workers fired their initial-delay Timer via `Timer(duration, _sweep)` and stored only the periodic ticker in the cancellable field — the one-shot Timer leaked past dispose and tripped the test framework's invariant check. Track both as _initialTimer + _intervalTimer; cancel both in dispose(). Behavior is unchanged in production (ref.onDispose only fires on process death normally); this is purely a test-harness fix.
This commit is contained in:
+6
-4
@@ -37,7 +37,8 @@ class CacheFiller {
|
|||||||
CacheFiller(this._ref);
|
CacheFiller(this._ref);
|
||||||
final Ref _ref;
|
final Ref _ref;
|
||||||
|
|
||||||
Timer? _timer;
|
Timer? _initialTimer;
|
||||||
|
Timer? _intervalTimer;
|
||||||
bool _running = false;
|
bool _running = false;
|
||||||
bool _disposed = false;
|
bool _disposed = false;
|
||||||
|
|
||||||
@@ -61,8 +62,8 @@ class CacheFiller {
|
|||||||
static const _maxIdsPerSweep = 200;
|
static const _maxIdsPerSweep = 200;
|
||||||
|
|
||||||
void start() {
|
void start() {
|
||||||
Timer(_initialDelay, _sweep);
|
_initialTimer = Timer(_initialDelay, _sweep);
|
||||||
_timer = Timer.periodic(_interval, (_) => _sweep());
|
_intervalTimer = Timer.periodic(_interval, (_) => _sweep());
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _sweep() async {
|
Future<void> _sweep() async {
|
||||||
@@ -217,7 +218,8 @@ class CacheFiller {
|
|||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
_timer?.cancel();
|
_initialTimer?.cancel();
|
||||||
|
_intervalTimer?.cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-4
@@ -91,7 +91,8 @@ class MutationReplayer {
|
|||||||
MutationReplayer(this._ref);
|
MutationReplayer(this._ref);
|
||||||
final Ref _ref;
|
final Ref _ref;
|
||||||
|
|
||||||
Timer? _timer;
|
Timer? _initialTimer;
|
||||||
|
Timer? _intervalTimer;
|
||||||
bool _running = false;
|
bool _running = false;
|
||||||
bool _disposed = false;
|
bool _disposed = false;
|
||||||
|
|
||||||
@@ -109,7 +110,7 @@ class MutationReplayer {
|
|||||||
// Drain shortly after launch in case there are queued mutations
|
// Drain shortly after launch in case there are queued mutations
|
||||||
// from a prior session that died offline. 3s lets the auth +
|
// from a prior session that died offline. 3s lets the auth +
|
||||||
// server-url + dio providers finish their async warmup.
|
// server-url + dio providers finish their async warmup.
|
||||||
Timer(const Duration(seconds: 3), drain);
|
_initialTimer = Timer(const Duration(seconds: 3), drain);
|
||||||
|
|
||||||
// Drain on every connectivity emission that resolves to online.
|
// Drain on every connectivity emission that resolves to online.
|
||||||
// ref.listen fires on changes after subscription; we don't get
|
// ref.listen fires on changes after subscription; we don't get
|
||||||
@@ -120,7 +121,7 @@ class MutationReplayer {
|
|||||||
if (isOnline) unawaited(drain());
|
if (isOnline) unawaited(drain());
|
||||||
});
|
});
|
||||||
|
|
||||||
_timer = Timer.periodic(_interval, (_) => drain());
|
_intervalTimer = Timer.periodic(_interval, (_) => drain());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Walk the queue oldest-first, replaying each mutation. Stops on
|
/// Walk the queue oldest-first, replaying each mutation. Stops on
|
||||||
@@ -214,7 +215,8 @@ class MutationReplayer {
|
|||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
_timer?.cancel();
|
_initialTimer?.cancel();
|
||||||
|
_intervalTimer?.cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user