You meet this pattern a lot when you do network programming - a buffer that flushes upon reaching either a space or a time limit, whichever comes first. Limits of 2-3 secs and/or 100-200 events are often used as a basis for further tuning.
I’d needed this construct a lot lately, and having built it and re-built it a couple of times, arrived at the Scalaz Actor-based version below. If you don’t need proof with your theorems, the complete Gist can be had here. If you do, follow me as we build it from scratch.
The core idea is obviously simple - accept message, put them in a private buffer, and once size or time limitation has been reached, flush. We’ll start with the size bound - it’s easier. We’ll use - horror of horrors - a mutable ArrayBuffer too - it’s a lot more performance than the immutable List.
Since we’re using Scalaz’s Actor, which is a final case class, we can’t extend it (really, for the better), so we’ll wrap around it instead like so:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
Flushing on time
The above buffer works for size, but threatens to become a morass if the flow over it is slow, backing the world up until it collects its
bufferSize messages. The common solution is to force a flush at timed intervals regardless of the current buffer size.
Since the only way to talk to a Scalaz Actor is to send messages to it (a good thing), and since it’s strongly-typed (also a good thing), we’ll need an Algebraic Data Type that can represent both our payload messages, and a flush timer, like so:
1 2 3
We’ll also need a timer to send those
Flush objects at a regular intervals, so we whip up a quick convenience wrapper around
1 2 3 4 5 6 7 8 9 10 11 12
Putting it all together
All we have left is to start the timer, which we can simply do in the body of
BufferActor since in Scala class bodies are essentially constructor code. Behold:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
Note that the
actoris lazy. This is to avoid a race condition that can otherwise occur between the initialization of the class and the firing of the timer.
It’s highly advised that you remove it and see what happens.
As mentioned before, the complete Gist can be had here. Enjoy!