/stateless-future-akka

The ultimate solution to control flow of Akka actors

Primary LanguageScalaApache License 2.0Apache-2.0

Stateless Future For Akka

Build Status

stateless-future-akka allows you to build control flow for Akka actor in the native Scala syntax. stateless-future-akka bases on stateless-future, which is a better future system than scala.concurrent.Future.

Usage

Step 1: Mix-in FutureFactory with your Actor

import com.qifun.statelessFuture.akka.FutureFactory
import akka.actor._
class YourActor extends Actor with FutureFactory {
}

Step 2: Implement the receive method from a Future block

import com.qifun.statelessFuture.akka.FutureFactory
import akka.actor._
class YourActor extends Actor with FutureFactory {
  override def receive = Future {
  	???
  }
}

Step 3: Receive and send message in the Future block

There is a magic method nextMessage.await that receive the next message from the actor's mail box. Unlike a normal Actor.Receive, You are able to receive multiple message sequentially in a Future block:

import com.qifun.statelessFuture.akka.FutureFactory
import akka.actor._
class YourActor extends Actor with FutureFactory {
  override def receive = Future {
    while (true) {
      val message1 = nextMessage.await
      val message2 = nextMessage.await
      sender ! s"You have sent me $message1 and $message2"
    }
    throw new IllegalStateException("Unreachable code!")
  }
}

Note that the Future block for receive must receive all the message until the actor stops. In fact, the def receive = Future { ??? } is a shortcut of def receive = FutureFactory.receiveForever(Future[Nothing] { ??? }).

Another example

This example creates an actor that concatenates arbitrary number of strings.

import com.qifun.statelessFuture.akka.FutureFactory
import akka.actor._
import scala.concurrent.duration._

class ConcatenationActor extends Actor with FutureFactory {
  def nextInt: Future[Int] = Future {
    nextMessage.await.toString.toInt
  }
  override def receive = Future {
    while (true) {
      // Should behave the same as:
      // val numberOfSubstrings = nextMessage.await.toString.toInt
      val numberOfSubstrings = nextInt.await
      var i = 0
      val sb = new StringBuilder
      while (i < numberOfSubstrings) {
        sb ++= nextMessage.await.toString
        i += 1
      }
      val result = sb.toString
      println(result)
      sender ! result
    }
    throw new IllegalStateException("Unreachable code!")
  }
}

object ConcatenationActor {
  def main(arguments: Array[String]) {
    val system = ActorSystem("helloworld")
    val concatenationActor = system.actorOf(Props[ConcatenationActor], "concatenationActor")
    val inbox = Inbox.create(system)
    inbox.send(concatenationActor, "4")
    inbox.send(concatenationActor, "Hello")
    inbox.send(concatenationActor, ", ")
    inbox.send(concatenationActor, "world")
    inbox.send(concatenationActor, "!")
    assert(inbox.receive(5.seconds) == "Hello, world!")
    inbox.send(concatenationActor, "2")
    inbox.send(concatenationActor, "Hello, ")
    inbox.send(concatenationActor, "world, again!")
    assert(inbox.receive(5.seconds) == "Hello, world, again!")
  }
}

Installation

Put these lines in your build.sbt if you use Sbt:

libraryDependencies += "com.qifun" %% "stateless-future-akka" % "0.1.1"

stateless-future-akka should work with Scala 2.10.3, 2.10.4, or 2.11.0.

Links