In my project I'm using Akka's Actors. By definition Actors are thread-safe, which means that in the Actor's receive method
def receive = {
case msg =>
// some logic here
}
only one thread at a time processes the commented piece of code. However, things are starting to get more complicated when this code is asynchronous:
def receive = {
case msg =>
Future {
// some logic here
}
}
If I understand this correctly, in this case only the Future construct will be synchronized, so to speak, and not the logic inside the Future.
Of course I may block the Future:
def receive = {
case msg =>
val future = Future {
// some logic here
}
Await.result(future, 10.seconds)
}
which solves the problem, but I think we all should agree that this is hardly an acceptable solution.
So this is my question: how can I retain the thread-safe nature of actors in case of asynchronous computing without blocking Scala's Futures?
How can I retain the thread-safe nature of actors in case of
asynchronous computing without block Scalas Future?
This assumption is only true if you modify the internal state of the actor inside the Future which seems to be a design smell in the first place. Use the future for computation only by creating a copy of the data and pipe to result of the computation to the actor using pipeTo. Once the actor receives the result of the computation you can safely operate on it:
import akka.pattern.pipe
case class ComputationResult(s: String)
def receive = {
case ComputationResult(s) => // modify internal state here
case msg =>
Future {
// Compute here, don't modify state
ComputationResult("finished computing")
}.pipeTo(self)
}
I think you need to "resolve" the db query first and then use the result to return a new Future. If the db query returns a Future[A], then you can use flatMap to operate over A and return a new Future. Something in the lines of
def receive = {
case msg =>
val futureResult: Future[Result] = ...
futureResult.flatMap { result: Result =>
// ....
// return a new Future
}
}
the simplest solution here is to turn the actor into a state machine (use AkkaFSM) and do the following:
dispatch a future for the mongoDB request.
use the reference to your own actor to commuincate with your actor
tell the message back from the future.
depending on context you might have to do some more to get a proper response.
But this has the advantage that you process the message with the actor state and you can mutate the actor state as you please as you own the thread.
Related
What is the proper way to handle Futures from inside an Akka (typed) Actor?
For example, assume there is an Actor OrderActor that receives Commands to place orders... which it does by making an http call to an external service. Since these are http calls to an external service, Futures are involved. So, what is the right way to handle that Future from within the Actor.
I read something about the pipeTo pattern. Is that what needs to happen here or something else?
class OrderActor(context: ActorContext[OrderCommand], orderFacade: OrderFacade)
extends AbstractBehavior[OrderCommand](context) {
context.log.info("Order Actor started")
override def onMessage(msg: OrderCommand): Behavior[OrderCommand] = {
msg match {
case PlaceOrder(
referenceId: OrderReferenceId,
ticker: Ticker,
quantity: Int,
replyTo: ActorRef[OrderResult]
) =>
orderFacade
.placeOrder(ticker, quantity) //this returns a Future
.map(res => {
//transform result
//book keeping / notification (affects state)
replyTo ! transformed
//Can/Should we map like this? I tried adding a log statement in here, but I never see it... and the replyTo doesnt seem to get the message.
})
this
It's generally best to avoid doing Future transformations (map, flatMap, foreach, etc.) inside an actor. There's a distinct risk that some mutable state within the actor isn't what you expect it to be when the transformation runs. In Akka Classic, perhaps the most pernicious form of this would result in sending a reply to the wrong actor.
Akka Typed (especially in the functional API) reduces a lot of the mutable state which could cause trouble, but it's still generally a good idea to pipe the Future as a message to the actor.
So if orderFacade.placeOrder results in a Future[OrderResponse], you might add subclasses of OrderCommand like this
// also include fields from the PlaceOrder which will be useful
case class OrderResponseIs(resp: OrderResponse, replyTo: ActorRef[OrderResult]) extends OrderCommand
// TODO include fields
case class OrderFailed() extends OrderCommand
And then pipe the Future to yourself with:
import scala.util.{ Failure, Success }
context.pipeToSelf(orderFacade.placeOrder) {
case Success(resp) => OrderResponseIs(resp, replyTo)
case Failure(_) => OrderFailed()
}
You then have to handle those messages:
case OrderResponseIs(resp, replyTo) =>
// transform resp
val transformed = ???
replyTo ! transformed
this
case OrderFailed() =>
context.log.warning("Stuff is broken")
this
There's not actually much overhead in doing this versus map and friends (both will typically involve scheduling a task for asynchronous execution on the dispatcher).
My Akka actor acquires some resources, which should be released after jobs are done, as shown by code snippet below.
The issue is, how to make sure the resources will be released in case of exceptions.
The first idea occurred to me is to assign the acquired resources to a var, and release them in def postStop() hook as a safeguard.
As this is a such common requirement, I'm wondering if there's any best practice to this?
override def receive: Receive = {
case FILEIO(path) => {
val ios = fs.create(new Path(path))
// ios.read/write ..
// exception could occur
ios.close()
}
}
If you use scala 2.13 you can try scala.util.Using. It will close the resource automatically even if an exception occurs.
val resultTry = Using(fs.create(new Path(path))) { ios =>
// ios.read/write ..
// exception could occur
}
resultTry match {
case Success(ioOperationsResult) => ...
case Failure(ioException) => ...
}
Also, you should separate blocking IO operations from the akka dispatcher.
Use Akka Stream's File IO sinks and sources. The FileIO tools use actors under the covers, transparently close resources when errors occur, and run on a dedicated dispatcher. The latter is important because blocking IO operations should be isolated from the rest of the system. A simple example from the documentation:
import akka.stream.scaladsl._
val file = Paths.get("example.csv")
val foreach: Future[IOResult] = FileIO.fromPath(file).to(Sink.ignore).run()
I think you should reconsider using actors for heavy IO access.
Given that you're using a default dispatcher, you might block it with IO operations and this will slow down the whole actor system.
If you still wish to proceed, recommend doing following
Create a new dispatcher and assign it to your actor. See docs for reference
Use try/finally block to close resources (yes, plain old try/catch/finally)
override def receive: Receive = {
case FILEIO(path) => {
val ios = fs.create(new Path(path))
try {
// ios.read/write ..
// exception could occur
} finally {
ios.close()
}
}
}
Alternatively, extract your IO work into async context, like Future that should be executed in a dedicated execution context and use pipeTo pattern to process results with an Actor.
I have the following code in Scala:
val status: Future[String] = Await.ready(Http(address OK as.String), 1 second)
I'm making a http call and I'm waiting for an answer for a second.
I was told it's not good practice to block using Await.ready.
I'm curious what I can use instead.
Can I use for comprehensions? How?
It generally bad to block on an asynchronous operation, otherwise, why make it asynchronous at all?
You can use various implementations with Future[T], such as registering a continuation to invoke when the result arrives. For example, let's assume you want to parse the String result into a Foo object. You'd get:
val result: Future[Foo] = Http(address OK as.String).map {
s => parseJson[Foo](s)
}
Note that when working with Future[T], you'll end up bubbling them up the call chain of the execution, unless you synchronously block.
Same can be achieved with for comprehension:
for {
s <- Http(address OK as.String)
} yield (parseJson[Foo](s))
Using Await.ready is not a good practice because its blocking. In most of the cases you can compose and transform the futures to achieve the desired result.
But You can use blocking when its absolutely necessary. Here is my answer about blocking and its consequences When to and when not use blocking
Non-Blocking wait
def afterSomeTime(code: => Unit)(duration: FiniteDuration): Unit = {
someActorSystem.scheduler.scheduleOnce(duration) {
code
}
}
Above function will call the code after given duration, you can use any other timer implementation instead of Akka scheduler
case class TimeoutException(msg: String) extends Exception(msg)
def timeout[T](future: => Future[T])(duration: FiniteDuration)(implicit ec: ExecutionContext): Future[T] = {
val promise = Promise[T]()
future.onComplete(promise tryComplete)
afterSomeTime {
promise tryFailure TimeoutException(s"Future timeout after ${duration.toString()}")
}(duration)
promise.future
}
Given that we must avoid...
1) Modifying state
2) Blocking
...what is a correct end-to-end usage for a Future?
The general practice in using Futures seems to be transforming them into other Futures by using map, flatMap etc. but it's no good creating Futures forever.
Will there always be a call to onComplete somewhere, with methods writing the result of the Future to somewhere external to the application (e.g. web socket; the console; a message broker) or is there a non-blocking way of accessing the result?
All of the information on Futures in the Scaladocs - http://docs.scala-lang.org/overviews/core/futures.html seem to end up writing to the console. onComplete doesn't return anything, so presumably we have to end up doing some "fire-and-forget" IO.
e.g. a call to println
f onComplete {
case Success(number) => println(number)
case Failure(err) => println("An error has occured: " + err.getMessage)
}
But what about in more complex cases where we want to do more with the result of the Future?
As an example, in the Play framework Action.async can return a Future[Result] and the framework handles the rest. Will it eventually have to expect never to get a result from the Future?
We know the user needs to be returned a Result, so how can a framework do this using only a Unit method?
Is there a non-blocking way to retrieve the value of a future and use it elsewhere within the application, or is a call to Await inevitable?
Best practice is to use callbacks such as onComplete, onSuccess, onFailure for side effecting operations, e.g. logging, monitoring, I/O.
If you need the continue with the result of of your Future computation as opposed to do a side-effecting operation, you should use map to get access to the result of your computation and compose over it.
Future returns a unit, yes. That's because it's an asynchronous trigger. You need to register a callback in order to gather the result.
From your referenced scaladoc (with my comments):
// first assign the future with expected return type to a variable.
val f: Future[List[String]] = Future {
session.getRecentPosts
}
// immediately register the callbacks
f onFailure {
case t => println("An error has occurred: " + t.getMessage)
}
f onSuccess {
case posts => for (post <- posts) println(post)
}
Or instead of println-ing you could do something with the result:
f onSuccess {
case posts: List[String] => someFunction(posts)
}
Try this out:
import scala.concurrent.duration._
import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global
val f: Future[Int] = Future { 43 }
val result: Int = Await.result(f, 0 nanos)
So what is going on here?
You're defining a computation to be executed on a different thread.
So you Future { 43 } returns immediately.
Then you can wait for it and gather the result (via Await.result) or define computation on it without waiting for it to be completed (via map etc...)
Actually, the kind of Future you are talking about are used for side-effects. The result returned by a Future depends its type :
val f = Future[Int] { 42 }
For example, I could send the result of Future[Int] to another Future :
val f2 = f.flatMap(integer => Future{ println(integer) }) // may print 42
As you know, a future is a process that happens concurrently. So you can get its result in the future (that is, using methods such as onComplete) OR by explicitly blocking the current thread until it gets a value :
import scala.concurrent.Await
import akka.util.Timeout
import scala.concurrent.duration._
implicit val timeout = Timeout(5 seconds)
val integer = Await.result(Future { 42 }, timeout.duration)
Usually when you start dealing with asynchronous processes, you have to think in terms of reactions which may never occur. Using chained Futures is like declaring a possible chain of events which could be broken at any moment. Therefore, waiting for a Future's value is definitely not a good practice as you may never get it :
val integer = Await.result(Future { throw new RuntimeException() }, timeout.duration) // will throw an uncaught exception
Try to think more in terms of events, than in procedures.
Akka's documentation warns:
When using future callbacks, such as onComplete, onSuccess, and onFailure, inside actors you need to carefully avoid closing over the containing actor’s reference, i.e. do not call methods or access mutable state on the enclosing actor from within the callback
It seems to me that if I could get the Future which wants to access the mutable state to run on the same dispatcher that arranges for mutual exclusion of threads handling actor messages then this issue could be avoided. Is that possible? (Why not?)
The ExecutionContext provided by context.dispatcher is not tied to the actor messages dispatcher, but what if it were? i.e.
class MyActorWithSafeFutures {
implicit def safeDispatcher = context.dispatcherOnMessageThread
var successCount = 0
var failureCount = 0
override def receive: Receive = {
case MakeExternalRequest(req) =>
val response: Future[Response] = someClient.makeRequest(req)
response.onComplete {
case Success(_) => successCount += 1
case Failure(_) => failureCount += 1
}
response pipeTo sender()
}
}
}
Is there any way to do that in Akka?
(I know that I could convert the above example to do something like self ! IncrementSuccess, but this question is about mutating actor state from Futures, rather than via messages.)
It looks like I might be able to implement this myself, using code like the following:
class MyActorWithSafeFutures {
implicit val executionContext: ExecutionContextExecutor = new ExecutionContextExecutor {
override def execute(runnable: Runnable): Unit = {
self ! runnable
}
override def reportFailure(cause: Throwable): Unit = {
throw new Error("Unhandled throwable", cause)
}
}
override def receive: Receive = {
case runnable: Runnable => runnable.run()
... other cases here
}
}
Would that work? Why doesn't Akka offer that - is there some huge drawback I'm not seeing?
(See https://github.com/jducoeur/Requester for a library which does just this in a limited way -- for Asks only, not for all Future callbacks.)
Your actor is executing its receive under one of the dispatcher's threads, and you want to spin off a Future that's firmly attached to this particular thread? In that case the system can't reuse this thread to run a different actor, because that would mean the thread was unavailable when you wanted to execute the Future. If it happened to use that same thread to execute someClient, you might deadlock with yourself. So this thread can no longer be used freely to run other actors - it has to belong to MySafeActor.
And no other threads can be allowed to freely run MySafeActor - if they were, two different threads might try to update successCount at the same time and you'd lose data (e.g. if the value is 0 and two threads both try to do successCount +=1, the value can end up as 1 rather that 2). So to do this safely, MySafeActor has to have a single Thread that's used for itself and its Future. So you end up with MySafeActor and that Future being tightly, but invisibly, coupled. The two can't run at the same time and could deadlock against each other. (It's still possible for a badly-written actor to deadlock against itself, but the fact that all the code using that actor's "imaginary mutex" is in a single place makes it easier to see potential problems).
You could use traditional multithreading techniques - mutexes and the like - to allow the Future and MySafeActor to run concurrently. But what you really want is to encapsulate successCount in something that can be used concurrently but safely - some kind of... Actor?
TL;DR: either the Future and the Actor: 1) may not run concurrently, in which case you may deadlock 2) may run concurrently, in which case you will corrupt data 3) access state in a concurrency-safe way, in which case you're reimplementing Actors.
You could use a PinnedDispatcher for your MyActorWithSafeFutures actor class which would create a thread pool with exactly one thread for each instance of the given class, and use context.dispatcher as execution context for your Future.
To do this you have to put something like this in your application.conf:
akka {
...
}
my-pinned-dispatcher {
executor = "thread-pool-executor"
type = PinnedDispatcher
}
and to create your actor:
actorSystem.actorOf(
Props(
classOf[MyActorWithSafeFutures]
).withDispatcher("my-pinned-dispatcher"),
"myActorWithSafeFutures"
)
Although what you are trying to achieve breaks completely the purpose of the actor model. The actor state should be encapsulated, and actor state changes should be driven by incoming messages.
This does not answer your question directly, but rather offers an alternative solution using Akka Agents:
class MyActorWithSafeFutures extends Actor {
var successCount = Agent(0)
var failureCount = Agent(0)
def doSomethingWithPossiblyStaleCounts() = {
val (s, f) = (successCount.get(), failureCount.get())
statisticsCollector ! Ratio(f/s+f)
}
def doSomethingWithCurrentCounts() = {
val (successF, failureF) = (successCount.future(), failureCount.future())
val ratio : Future[Ratio] = for {
s <- successF
f <- failureF
} yield Ratio(f/s+f)
ratio pipeTo statisticsCollector
}
override def receive: Receive = {
case MakeExternalRequest(req) =>
val response: Future[Response] = someClient.makeRequest(req)
response.onComplete {
case Success(_) => successCount.send(_ + 1)
case Failure(_) => failureCount.send(_ + 1)
}
response pipeTo sender()
}
}
The catch is that if you want to operate on the counts that would result if you were using #volatile, then you need to operate inside a Future, see doSomethingWithCurrentCounts().
If you are fine with having values which are eventually consistent (there might be pending updates scheduled for the Agents), then something like doSometinghWithPossiblyStaleCounts() is fine.
#rkuhn explains why this would be a bad idea on the akka-user list:
My main consideration here is that such a dispatcher would make it very convenient to have multiple concurrent entry points into the Actor’s behavior, where with the current recommendation there is only one—the active behavior. While classical data races are excluded by the synchronization afforded by the proposed ExecutionContext, it would still allow higher-level races by suspending a logical thread and not controlling the intermediate execution of other messages. In a nutshell, I don’t think this would make the Actor easier to reason about, quite the opposite.