Rate-limited batch import
Requirement
Push nine ledger transactions (in the code below) to an import endpoint that accepts batches of three, one call at a time — strictly sequential, never overlapping. After each batch, record its size, its amount, and the running total imported so far; print the batch summaries in order, then prove the rate limit held via the max-in-flight counter (it must read 1).
In FxDart the whole policy is the chain: chunk(3) sets the
batch size, concurrent(1) sets the pace, and
scan threads the running total through the acknowledgments
(drop(1) discards the scan seed). The endpoint itself
simulates latency with delay and sums its batch with
sumBy.
Expected output
importing 9 txns in batches of 3, one at a time: batch 1: 3 txns, $172.49 — running total $172.49 batch 2: 3 txns, $403.65 — running total $576.14 batch 3: 3 txns, $325.34 — running total $901.48 max batches in flight: 1
Side by side
Native Dart
FxDart
Why they differ
To be fair: a strictly sequential import is the one concurrency policy a
plain for loop handles gracefully, and the native version
reads fine — slices from package:collection
even covers the batching. The running total, though, is already mutable
state threaded by hand (running += amount next to
n++), where scan makes it a declared step.
And the loop's simplicity is a dead end: the day the endpoint allows two
concurrent batches, the FxDart version changes 1 to
2, while the loop becomes the worker pool from the other
async examples. The chain states the policy; the loop encodes it.
Benchmark
Async case: the headline scale is N = 100,000, not 1,000,000. Every element costs an event-loop turn on both sides, so a million real awaits would measure Dart's event loop for minutes — not the pipeline. Delays are zero-length and the example's concurrency limit is kept; what the bars compare is the pipeline machinery.
N = 100
Time Tie
Peak memory Tie
N = 10,000
Time Native wins
Peak memory Native wins
N = 100,000
Time Native wins
Peak memory Tie
Bars are medians of repeated timed iterations in fresh processes per side (small N is batched for timer resolution). Sides within 5% of each other — or within 0.6 ms, a difference no person can perceive — count as a tie; close relative races are re-measured up to 5 runs. In an app, anything under a few milliseconds is invisible to the user regardless of which bar is shorter. Memory is peak process RSS. The Dart VM and the dataset are identical on both sides, so the difference between the two bars is what the pipeline itself holds onto.