Skip to content

Instantly share code, notes, and snippets.

@ornicar
Created May 13, 2014 08:16
Show Gist options
  • Save ornicar/0d9354abbe364fc3ae01 to your computer and use it in GitHub Desktop.
Save ornicar/0d9354abbe364fc3ae01 to your computer and use it in GitHub Desktop.
/**
* Ensure asynchronous functions are run sequentially.
* This implementation is for Future[Unit],
* so the work is sent in fire-and-forget style,
* and we don't care about the function result.
*
* Usage:
* val sequencer = new Sequencer
* sequencer ! Sequencer.work(updateDatabaseAsynchronously)
* sequencer ! Sequencer.work(moreUpdate)
*
* the `moreUpdate` function will be called when `updateDatabaseAsynchronously` completes.
*/
final class Sequencer extends Actor {
private def idle: Receive = {
case msg =>
context become busy
processThenDone(msg)
}
private def busy: Receive = {
case Done => dequeue match {
case None => context become idle
case Some(work) => processThenDone(work)
}
case msg => queue enqueue msg
}
def receive = idle
private val queue = collection.mutable.Queue[Any]()
private def dequeue: Option[Any] = Try(queue.dequeue).toOption
private case object Done
private def processThenDone(work: Any) {
work match {
case Sequencer.Work(run) => run() andThenAnyway { self ! Done }
case x => play.api.Logger("Sequencer").warn(s"Unsupported message $x")
}
}
}
object Sequencer {
case class Work(run: () => Funit)
def work(run: => Funit): Work = Work(() => run)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment