Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The actor pattern with Akka and long running processes

Lately I have been investigating the awesome Akka framework to try to get a feel for it and decide if it would be right for my project. Currently this application is a plain old java application that performs some very complex calculations by making calls to various external c++ executable's (sometimes the calculations can take hours to run). In code it would look something like this

public static class Worker extends UntypedActor {
  // Run Very Long Process 
  public void onReceive(Object message) {
    if (message instanceof Work) {
        Work work = (Work) message;
        double result = veryLongProcess(work.getStart(),work.getNrOfElements());
        getSender().tell(new Result(result), getSelf());
    } else {
       unhandled(message);
    }
  }
}

My question is can Akka handle actors taking sometimes hours to return from their execution?

like image 369
Jake C. Avatar asked Nov 13 '15 20:11

Jake C.


2 Answers

Answering your question directly; there is a good article on this very topic:

Again, if you have long-running computations, having them run in a separate ExecutionContext for CPU-bound tasks is a good idea.

The article has the following example:

import java.util.concurrent.Executors
import concurrent.ExecutionContext

//I added 'private' for the rest of the example
private val executorService = Executors.newFixedThreadPool(4)
private val executionContext = ExecutionContext.fromExecutorService(executorService)

Answering indirectly,

Futures First

I completely agree that Akka Actors are a very useful tool for particular types of work. When it comes to caching, Actors & Agents are the best game in town.

However, in this instance I would suggest leveraging a Future instead of an Actor. You could make veryLongProcess a private function. The privacy would allow complete control over the number of threads calling the method at once:

def longProcessFut(start : Int, noOfElements : Int) : Future[Result] = Future {
  veryLongProcess(start, noOfElements)
}(executionContext)//controls the executing pool of veryLongProcess

Simple, concise, and asynchronous.

No killing of letters, no overloaded receive method that accepts anything under the sun, nor Props, not even an ActorRef was necessary for the Future. Bloat, beer belly I say!

Besides, your user is going to create a Future no matter what because of ?:

//Actor user code, too verbose

val longProcessRef = actorSystem actorOf Props[Worker]

val fut : Future[Result] = (longProcessRef ? Work(0,42)).mapTo[Result]

Compared to using Futures directly

//happy user code

val fut : Future[Result] = longProcessFut(0, 42)

Same great Future, but half the calories!

You can control the dispatcher of the Future in the same manner(s) as suggested in the comments, which are quite good. You can even use actorSystem.dispatcher as your Future dispatcher to control the dispatcher behavior.

like image 199
Ramón J Romero y Vigil Avatar answered Sep 29 '22 06:09

Ramón J Romero y Vigil


If the long running business logic / algorithm is incremental, produces intermediate results and/or can run for a very long time then you may want to reuse excellent design snippets from here: Incremental processing in an akka actor

like image 34
SemanticBeeng Avatar answered Sep 29 '22 07:09

SemanticBeeng