As the doc of akka explains, you should be able to gain the pipeTo method on [[scala.concurrent.Future]] this way:
import akka.pattern.pipe
val future = ...
future pipeTo sender()
Unfortunately, I can't do that, i'm getting an error "can't resolve symbol pipeTo" in my IDE.
As a workaround, I had to use the syntax this way
pipe(future) pipeTo sender()
But it still disturb me to not figure out why (i'm quite newby in scala BTW). Thanks a lot to help understand this puzzle.
scala 2.12.2
akka 2.5.3
You need to have an implicit ExecutionContext in scope, here is an example:
import akka.actor.{Actor, ActorSystem, Props}
import akka.pattern.pipe
import scala.concurrent.Future
// Get the implicit ExecutionContext from this import
import scala.concurrent.ExecutionContext.Implicits.global
object Hello extends App {
// Creating a simple actor
class MyActor extends Actor {
override def receive: Receive = {
case x => println(s"Received message: ${x.toString}")
}
}
// Create actor system
val system = ActorSystem("example")
val ref = system.actorOf(Props[MyActor], "actor")
// Create the future to pipe
val future: Future[Int] = Future(100)
// Test
future pipeTo ref
}
Console:
sbt run
[info] <stuff here>
[info] Running example.Hello
Received message: 100
The reason you have to do that is because pipeTo is a instance function on a PipeableFuture, and your regular Future has to be "enhanced" to a PipeableFuture. Here is the constructor for PipeableFuture, note the implicit executionContext: ExecutionContext parameter:
final class PipeableFuture[T](val future: Future[T])(implicit executionContext: ExecutionContext)
The full class is here, where you can see the pipeTo function:
final class PipeableFuture[T](val future: Future[T])(implicit executionContext: ExecutionContext) {
def pipeTo(recipient: ActorRef)(implicit sender: ActorRef = Actor.noSender): Future[T] = {
future andThen {
case Success(r) ⇒ recipient ! r
case Failure(f) ⇒ recipient ! Status.Failure(f)
}
}
def pipeToSelection(recipient: ActorSelection)(implicit sender: ActorRef = Actor.noSender): Future[T] = {
future andThen {
case Success(r) ⇒ recipient ! r
case Failure(f) ⇒ recipient ! Status.Failure(f)
}
}
def to(recipient: ActorRef): PipeableFuture[T] = to(recipient, Actor.noSender)
def to(recipient: ActorRef, sender: ActorRef): PipeableFuture[T] = {
pipeTo(recipient)(sender)
this
}
def to(recipient: ActorSelection): PipeableFuture[T] = to(recipient, Actor.noSender)
def to(recipient: ActorSelection, sender: ActorRef): PipeableFuture[T] = {
pipeToSelection(recipient)(sender)
this
}
}
Since pipe(future) was not an instance function on a Future, it works in your example.
Related
I am wondering what the canonical way is of testing whether an actor has stopped in akka. Here is an example of how I am currently doing; I'm worried I'm over complicating it.
import akka.actor.{Terminated, Actor, Props, ActorSystem}
import akka.testkit.TestProbe
class MyActor extends Actor {
import MyActor._
override def receive: Receive = {
case Stop => context.stop(self)
}
}
object MyActor {
def props = Props(new MyActor)
case object Stop
}
object MyActorSpec {
val system = ActorSystem()
val myActor = system.actorOf(MyActor.props)
val testProbe = TestProbe()
case object MyActorStopped
val watcher = system.actorOf(Props(new Actor {
context.watch(myActor)
override def receive: Actor.Receive = {
case Terminated(`myActor`) => testProbe.ref ! MyActorStopped
}
}))
myActor ! MyActor.Stop
testProbe.expectMsg(MyActorStopped)
}
You can get rid of the separate watcher actor, and just watch the target actor directly from the testProbe actor:
val testProbe = TestProbe()
testProbe watch myActor
myActor ! MyActor.Stop
testProbe.expectTerminated(myActor)
See here for the relevant section of the Akka testing docs.
Trying to schedule tasks like this in Play Framework 2.4.2 Scala without luck:
import akka.actor.Actor
import play.api.libs.concurrent.Akka
import scala.concurrent.duration._
import play.api.Play.current
import scala.concurrent.ExecutionContext.Implicits.global
class Scheduler extends Actor {
override def preStart() {
val dbupdate = Akka.system.scheduler.schedule(
0.microseconds, 5.minutes, self, "update")
val pictureClean = Akka.system.scheduler.schedule(
0.microseconds, 30.minutes, self, "clean")
}
def receive = {
case "update" => updateDB()
case "clean" => clean()
}
def updateDB(): Unit ={
Logger.debug("updates running")
}
def clean(): Unit ={
Logger.debug("cleanup running")
}
}
Nothing is printed in console. What I'm doing wrong?
Ok. Here working code of scheduler I've built:
Module:
class JobModule extends AbstractModule with AkkaGuiceSupport {
def configure() = {
bindActor[SchedulerActor]("scheduler-actor")
bind(classOf[Scheduler]).asEagerSingleton()
}
}
Scheduler:
class Scheduler #Inject() (val system: ActorSystem, #Named("scheduler-actor") val schedulerActor: ActorRef)(implicit ec: ExecutionContext)
{
system.scheduler.schedule(
0.microseconds, 5.minutes, schedulerActor, "update")
system.scheduler.schedule(
30.minutes, 30.days, schedulerActor, "clean")
}
Actor:
#Singleton
class SchedulerActor #Inject() (updater: Updater) extends Actor {
def receive = {
case "update" => updateDB()
case "clean" => clean()
}
def updateDB(): Unit ={
Logger.debug("updates running")
}
def clean(): Unit ={
Logger.debug("cleanup running")
}
}
You also need to add your module in application.conf:
play.modules.enabled += "modules.JobModule"
Hope this will help someone
Try
context.system.scheduler.schedule
And also make sure you have logging at Debug level otherwise those messages won't make it to the console. If you're unsure try changing them to Logger.error temporarily.
I am fairly new to akka and not sure about approaching this problem.
I have a Monitor actor that spawns 2 other actors as DiskMonitor and MemoryMonitor
DiskMonitor checks the diskUsage and report DiskReport message
MemoryMonitor checks the diskUsage and report MemoryReport message
I want to combine the DiskReport and MemoryReport into Report Object and send to to remote machine via an API.
Questions
Since DiskMonitor and MemoryMonitor both are actors they send the response back to caller once they are done with their work
Monitor
diskMonitor ! DiskMonitorRequest
memoryMonitor ! MemoryMonitorRequest
How would Monitor know that it has all the results that it needs so that it can create Report object and send it via API?
Are actors good way to approach this problem?
I also read about future but I don't understand them well and not sure if they would be helpful in this problem context
This is a simple way of doing these things. Other options can be through using context.become or the trait FSM.
class Monitor extends Actor {
// Somewhere do this:
diskMonitor ! DiskMonitorRequest
memoryMonitor ! MemoryMonitorRequest
var diskMonitorResult = Option.empty[DiskMonitor]
var memoryMonitorResult = Option.empty[MemoryMonitor]
def recieve = {
case d: DiskMonitor =>
diskMonitorResult = Some(d)
checkIfCompleted()
case m: MemoryMonitor =>
memoryMonitorResult = Some(m)
checkIfCompleted()
}
def checkIfCompleted = {
(diskMonitorResult, memoryMonitorResult) match {
case (Some(diskMonitor), Some(memoryMonitor)) =>
// send to external API
externalApi ! Report(diskMonitor, memoryMonitor)
// Possibly stop this actor
case _ => // do nothing
}
}
}
You can use ask pattern and combine futures..
import akka.actor._
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.ExecutionContextExecutor
import scala.concurrent.duration._
import scala.language.postfixOps
class Monitor extends Actor with ActorLogging {
implicit val timeout: Timeout = Timeout(5 seconds)
implicit val ec: ExecutionContextExecutor = context.dispatcher
val diskM: ActorRef = context.system.actorOf(Props[DiskMonitor])
val memoryM: ActorRef = context.system.actorOf(Props[MemoryMonitor])
val remoteM: ActorRef = context.system.actorOf(Props[RemoteMachine])
override def preStart: Unit = {
log.info("Monitor Created..")
self ! GenerateReport
}
override def receive: Receive = {
case GenerateReport =>
(diskM ? MakeDiskReport).mapTo[DiskReport].zip((memoryM ? MakeMemoryReport)
.foreach { case (diskR, memR) =>
remoteM ! Report(memR.report, diskR.report)
}
}
}
class DiskMonitor extends Actor with ActorLogging {
override def receive: Receive = {
case MakeDiskReport =>
log.info("Creating DiskReport..")
val client = sender
client ! DiskReport("DiskReport")
}
}
class MemoryMonitor extends Actor with ActorLogging {
override def receive: Receive = {
case MakeMemoryReport =>
log.info("Creating MemoryReport..")
val client = sender
client ! MemoryReport("MemoryReport")
}
}
class RemoteMachine extends Actor with ActorLogging {
override def receive: Receive = {
case Report(memr, diskr) =>
log.info(s"Final Report.. $memr, $diskr")
}
}
object Main extends App {
val sys = ActorSystem()
sys.actorOf(Props[Monitor])
}
sealed trait Message
case object GenerateReport extends Message
case object MakeDiskReport extends Message
case object MakeMemoryReport extends Message
case class DiskReport(report: String) extends Message
case class MemoryReport(report: String) extends Message
case class Report(memReport: String, diskReport: String) extends Message
Akka and Scala newbie here, please feel free to edit the question as necessary in order to clearly articulate my intent in the domain of Scala and Akka.
Before I show code snippets, here's the problem I want to solve: I essentially want to develop a common module for my team to use when they're developing their applications using Akka actors. I want to allow them to mixin a trait which will extend their receive functionality at runtime, mainly for logging purposes. I'm running into compile errors, which I'll explain soon.
But first, take for example, a simple main:
object Test extends App {
val system = ActorSystem("system")
val myActor = system.actorOf(Props(new MyActor), "myActor")
myActor ! "Hello world!"
}
Here's an example implementation of an actor that a team member might implement in his application:
class MyActor extends Actor with ActorLogger {
override def receive: Receive = {
case msg => {
log.info("testing ...")
}
case _ => throw new RuntimeException("Runtime Ex")
}
}
And here's an example of how I would provide a common trait for them to mixin:
trait ActorLogger extends Actor {
val log: DiagnosticLoggingAdapter = Logging(this)
abstract override def receive: Receive = {
case msg: Any => {
if (msg.isInstanceOf[String]) {
println("enter")
log.mdc(Map[String, Any]("someKey" -> 123))
super.receive(msg)
log.clearMDC()
println("exit")
}
}
case _ => throw new RuntimeException("Runtime Ex")
}
}
As you can see, I'm trying to add data to an MDC if the message so happens to be String (a basic example, in reality, I would check for some custom type of our own).
The error I get is:
Error:(29, 16) overriding method receive in trait ActorLogger of type =>
MyActor.this.Receive;
method receive needs `abstract override' modifiers
override def receive: Receive = {
^
What's wrong here? And is stackable traits the right to go away to achieve something like this? If not, what is the most idiomatic way?
More generally, is there another pattern being applied here besides "interceptor" pattern?
Thanks for all the help!
A solution without a hack with akka package:
import akka.actor.{Actor, ActorSystem, Props}
trait MyActorExtension extends Actor {
def receiveExtension: Receive = PartialFunction.empty
}
abstract class MyActor extends MyActorExtension {
protected def receiveMsg: Receive
def receive: Receive = receiveExtension orElse receiveMsg
}
trait ActorLogger1 extends MyActor with MyActorExtension {
abstract override def receiveExtension = {
case msg =>
println(s"********** Logging # 1: $msg")
super.receiveExtension.applyOrElse(msg, receiveMsg)
}
}
trait ActorLogger2 extends MyActor with MyActorExtension {
abstract override def receiveExtension = {
case msg =>
println(s"########## Logging # 2: $msg")
super.receiveExtension.applyOrElse(msg, receiveMsg)
}
}
class SpecificActor extends MyActor with ActorLogger1 with ActorLogger2 {
def receiveMsg = {
case someMsg =>
println(s"SpecificActor: $someMsg")
}
}
object Test extends App {
val system = ActorSystem("system")
val mySpecificActor = system.actorOf(Props(new SpecificActor), "SpecificActor")
mySpecificActor ! "Hello world!"
}
#### Logging # 2: Hello world!
****** Logging # 1: Hello world!
SpecificActor: Hello world!
aroundReceive is for Akka internal use and the stackable trair pattern is not that comfortable for this case.
I recommend you using Receive Pipeline for easy message interception.
I think that you need something like this
package akka
import akka.MsgsProt._
import akka.actor.{ Actor, ActorSystem, Props }
import scala.concurrent.duration._
sealed trait MsgProt
object MsgsProt {
case object FooMsg extends MsgProt
case object BarMsg extends MsgProt
}
trait Foo extends Actor {
override protected[akka] def aroundReceive(receive: Actor.Receive, msg: Any): Unit = msg match {
case FooMsg => println("Foo message")
case msg => super.aroundReceive(receive, msg)
}
}
trait Bar extends Actor {
override protected[akka] def aroundReceive(receive: Actor.Receive, msg: Any): Unit = msg match {
case BarMsg => println("Bar message")
case msg => super.aroundReceive(receive, msg)
}
}
class MyActor extends Actor with Foo with Bar {
override def receive: Actor.Receive = {
case _ => println("Nothing I know")
}
}
object Foo extends App {
val system = ActorSystem("foobar")
val myActor = system.actorOf(Props[MyActor])
implicit val timeout = 2 seconds
myActor ! FooMsg
myActor ! BarMsg
myActor ! "wrong message"
system.awaitTermination(10 seconds)
}
The output of this program is:
Foo message
Bar message
Nothing I know
Most important part is that package declaration - akka. Because method aroundReceive is limited only to akka package so you have to have some.package.akka and inside you can use that method aroundReceive. I think that it looks more like a hack not a solution but works. You can see more usage of this inside Akka itself ex. akka.DiagnosticActorLogging. But this is basically solution that you want to do with stacking Actors behaviour.
I'm trying to write a simple HTTP client using Scala and spray-client. I'm basing my client on the examples given on Spray docs.
My issue is that the example is creating a new implicit ActorSystem i.e.
implicit val system = ActorSystem()
but I want my client to be reusable and not create a new ActorSystem.
Here's the gist of my code.
trait WebClient {
def get(url: String)(implicit system: ActorSystem): Future[String]
}
object SprayWebClient extends WebClient {
val pipeline: HttpRequest => Future[HttpResponse] = sendReceive
def get(url: String): Future[String] = {
val r = pipeline (Get("http://some.url/"))
r.map(_.entity.asString)
}
}
But I am getting two compiler errors regarding implicits
implicit ActorRefFactory required: if outside of an Actor you need an implicit ActorSystem, inside of an actor this should be the implicit ActorContext WebClient.scala ...
and
not enough arguments for method sendReceive: (implicit refFactory: akka.actor.ActorRefFactory, implicit executionContext: scala.concurrent.ExecutionContext, implicit futureTimeout: akka.util.Timeout)spray.http.HttpRequest => scala.concurrent.Future[spray.http.HttpResponse]. Unspecified value parameters refFactory, executionContext. WebClient.scala...
How should I change the API definitions?
Here's one solution:
import akka.actor.ActorSystem
import spray.http.{HttpRequest, HttpResponse}
import scala.concurrent.Future
import spray.client.pipelining._
trait WebClient {
def get(url: String): Future[String]
}
class SprayWebClient(implicit system: ActorSystem) extends WebClient {
import system.dispatcher
val pipeline: HttpRequest => Future[HttpResponse] = sendReceive
def get(url: String): Future[String] = {
val r = pipeline (Get("http://some.url/"))
r.map(_.entity.asString)
}
}
and here's another that keeps the original WebClient.get signature:
import akka.actor.ActorSystem
import spray.http.{HttpRequest, HttpResponse}
import scala.concurrent.Future
import spray.client.pipelining._
trait WebClient {
def get(url: String)(implicit system: ActorSystem): Future[String]
}
object SprayWebClient extends WebClient {
def get(url: String)(implicit system: ActorSystem): Future[String] = {
import system.dispatcher
val pipeline: HttpRequest => Future[HttpResponse] = sendReceive
val r = pipeline (Get("http://some.url/"))
r.map(_.entity.asString)
}
}
The second one is a bit more expensive because the pipeline is created anew every time even if it is theoretically static per ActorSystem. I would prefer the first solution and try to find a way to propagate the WebClient through your application (by using the cake pattern, by passing it around explicitly, or by using other dependency injection techniques).