Dart
Future
async programming
concurrency
software development

Queue of Future in dart

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

A queue of Future tasks in Dart is useful when async work must run in a controlled order. Typical examples include sequential API writes, rate-limited requests, and state updates that cannot overlap. A good design defines execution policy explicitly: serial, bounded parallel, or fail-fast.

Core Sections

1. Queue deferred tasks, not already running futures

A common mistake is enqueuing started futures. By the time they reach queue execution, they may already be running. Instead, enqueue functions that create futures when executed.

dart
1import 'dart:collection';
2
3final Queue<Future<void> Function()> queue = Queue();
4
5queue.add(() async {
6  // task starts only when dequeued
7});

This keeps execution control deterministic.

2. Basic serial queue runner

For strict ordering, execute one task at a time.

dart
1import 'dart:async';
2import 'dart:collection';
3
4class SerialQueue {
5  final Queue<Future<void> Function()> _tasks = Queue();
6  bool _running = false;
7
8  Future<void> add(Future<void> Function() task) {
9    final completer = Completer<void>();
10    _tasks.add(() async {
11      try {
12        await task();
13        completer.complete();
14      } catch (e, st) {
15        completer.completeError(e, st);
16      }
17    });
18    _drain();
19    return completer.future;
20  }
21
22  void _drain() {
23    if (_running) return;
24    _running = true;
25
26    Future<void>(() async {
27      while (_tasks.isNotEmpty) {
28        final task = _tasks.removeFirst();
29        await task();
30      }
31      _running = false;
32    });
33  }
34}

This guarantees order and isolates task errors per enqueue call.

3. Tail-future chaining pattern

Another serial pattern is chaining on a tail future.

dart
1import 'dart:async';
2
3class ChainedExecutor {
4  Future<void> _tail = Future.value();
5
6  Future<T> enqueue<T>(Future<T> Function() task) {
7    final completer = Completer<T>();
8
9    _tail = _tail.then((_) async {
10      try {
11        final result = await task();
12        completer.complete(result);
13      } catch (e, st) {
14        completer.completeError(e, st);
15      }
16    }).catchError((_) {});
17
18    return completer.future;
19  }
20}

This is compact and works well when many producers enqueue tasks.

4. Error policy: continue or stop

Define queue behavior on failure:

  • continue processing next tasks
  • stop queue and surface fatal state

The right choice depends on domain semantics. For user-request queues, continuing is often preferred. For financial transaction queues, fail-fast may be safer.

Document policy explicitly so callers know expectations.

5. Bounded concurrency instead of full serialization

Sometimes strict serial execution is too slow. Use limited parallelism with a worker count.

dart
1import 'dart:async';
2import 'dart:collection';
3
4class LimitedExecutor {
5  final int concurrency;
6  int _running = 0;
7  final Queue<Future<void> Function()> _pending = Queue();
8
9  LimitedExecutor(this.concurrency);
10
11  Future<void> add(Future<void> Function() task) {
12    final completer = Completer<void>();
13    _pending.add(() async {
14      try {
15        await task();
16        completer.complete();
17      } catch (e, st) {
18        completer.completeError(e, st);
19      }
20    });
21    _drain();
22    return completer.future;
23  }
24
25  void _drain() {
26    while (_running < concurrency && _pending.isNotEmpty) {
27      final task = _pending.removeFirst();
28      _running++;
29      task().whenComplete(() {
30        _running--;
31        _drain();
32      });
33    }
34  }
35}

This improves throughput while retaining backpressure control.

6. Shutdown and cancellation behavior

Long-running queue services need graceful shutdown:

  • reject new tasks after shutdown request
  • wait for in-flight tasks with timeout
  • optionally persist pending tasks

Without shutdown protocol, app exits can drop queued work silently.

7. Testing queue guarantees

Add deterministic tests for:

  • strict execution order in serial mode
  • error propagation semantics
  • no task starvation under heavy enqueue load
  • shutdown behavior with pending tasks

Queue bugs are often race-dependent, so targeted tests are essential.

8. Integration with Streams and isolates

For high-throughput systems, queueing may feed from stream events or isolate messages. Keep boundary between intake and execution explicit so backpressure remains manageable.

A queue without backpressure can still overload downstream systems even if execution order is correct.

9. Observability for production queues

Track these metrics:

  • queue length
  • processing latency
  • failure rate
  • retry counts

Operational visibility is what turns queue behavior from guesswork into manageable SLO-driven engineering.

Common Pitfalls

  • Enqueuing already-started futures instead of deferred tasks.
  • Running multiple queue drainers and breaking order guarantees.
  • Ignoring failure policy and getting inconsistent behavior after errors.
  • Using strict serial mode where bounded concurrency is required.
  • Missing shutdown path and losing pending tasks during app termination.

Summary

  • Queueing futures in Dart is about explicit execution policy, not just syntax.
  • Use deferred task functions for deterministic control.
  • Pick serial or limited-concurrency execution based on correctness needs.
  • Define error and shutdown behavior clearly.
  • Add tests and metrics to keep queue behavior reliable in production.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.