@@ -22,30 +22,40 @@ typedef AsyncQueueBlock<T> = Future<T> Function();
2222/// Serial queue are often used to synchronize access to a specific value or resource to prevent data races to occur.
2323@internal
2424class AsyncQueue <T > {
25- static const _timeout = Duration (seconds: 30 );
26-
2725 final _blockS = StreamController <_AsyncQueueEntry <T >>();
28- final _countS = StreamController <int >(sync : true );
2926 late final DisposeBag _bag;
3027
31- /// Construct [AsyncQueue] .
32- AsyncQueue (Object key, void Function () onTimeout) {
28+ final _countS = StateSubject <int >(0 , sync : true );
29+
30+ /// Construct an [AsyncQueue] .
31+ AsyncQueue ({
32+ required Object key,
33+ required Duration timeout,
34+ required void Function () onTimeout,
35+ }) {
3336 _bag = DisposeBag (
3437 const < Object > [], '( AsyncQueue ~ $key ~ ${shortHash (this )} )' );
3538
3639 _blockS.disposedBy (_bag);
3740 _countS.disposedBy (_bag);
3841
39- final count$ = _countS.stream
40- .scan <int ?>((acc, value, _) => acc! + value, 0 )
41- .shareValueNotReplay (null );
42- count$
42+ // when the queue is empty, we wait for a timeout to occur
43+ // and then we call the onTimeout callback.
44+ _countS
4345 .where ((count) => count == 0 )
44- .switchMap ((_) => Rx .timer <void >(null , _timeout)
45- .where ((_) => count$.value == 0 )
46- .takeUntil (count$.where ((count) => count != null && count > 0 )))
47- .listen ((_) => onTimeout ())
48- .disposedBy (_bag);
46+ .switchMap ((_) => Rx .timer <void >(null , timeout)
47+ .where ((_) => _countS.value == 0 )
48+ .takeUntil (_countS.where ((count) => count > 0 )))
49+ .listen ((_) {
50+ assert (() {
51+ if (_countS.value != 0 ) {
52+ throw StateError ('AsyncQueue is not empty!' );
53+ }
54+ return true ;
55+ }());
56+
57+ onTimeout ();
58+ }).disposedBy (_bag);
4959
5060 Future <T > executeBlock (_AsyncQueueEntry <T > entry) {
5161 final completer = entry.completer;
@@ -64,7 +74,7 @@ class AsyncQueue<T> {
6474 }).onError <Object >((e, s) {
6575 completer.completeError (e, s);
6676 throw e;
67- }).whenComplete (() => _countS.add ( - 1 ) );
77+ }).whenComplete (() => _countS.value = _countS.value - 1 );
6878 }
6979
7080 _blockS.stream
@@ -73,7 +83,7 @@ class AsyncQueue<T> {
7383 .disposedBy (_bag);
7484 }
7585
76- /// Close queue.
86+ /// Close queue, discard all pending entries .
7787 Future <void > dispose () => _bag.dispose ();
7888
7989 /// Add block to queue.
@@ -87,7 +97,7 @@ class AsyncQueue<T> {
8797
8898 final completer = Completer <T >.sync ();
8999 _blockS.add (_AsyncQueueEntry (completer, block));
90- _countS.add ( 1 ) ;
100+ _countS.value = _countS.value + 1 ;
91101 return completer.future;
92102 }
93103}
0 commit comments