Learn

Learn about latest technology

Build

Unleash your talent and coding!

Share

Let more people use it to improve!
 

Akka an intelligent solution for concurrency

domingo, 10 de marzo de 2019


I am here because we needed a solution to a concurrency problem, access to hundreds of thousands of websites, parse and process  all of them asynchronously. I tried many options always with a main idea: Futures.
So coding in that way I made something similar to the following code:



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//....................

//game_1: Int value indicating first game 

//game_n: Int value indicating game n   

val resultMatch:List[Future[List[Match]]] = (game_1 until game_n).map {
 matchnum =>
  Future{
   new ParserFootbalHTML("https://www.anyurl.com/..." + matchnum).finalMatch
    }}.toList
//..............
resultMatch foreach(future => future onComplete {
 Thread.sleep(1)
 doComplete
})
//...............
def doComplete: PartialFunction[Try[List[Match]],Unit] = { //
 case matches @ Success(_) =>{
  val resultMatch:List[Match] = matches.getOrElse(List.empty[Match])
    resultMatch.foreach(matches=>
//Do anything with matches
  )
 }
 case fail @ Failure(_) => println("error")
}
//....................

With minimal changes the main idea was to launch as many "Futures" as web sites we need to parse. Then after every computation finish(onComplete) I will do "anything" with  the result. So after several test in different escenarios checking how long time did it take I decided to explore Akka, for improve performance and reduce time of calculation.
The Core of Akka libraries is the Actor Model, I recommend understand it because is the base of this libraries. Akka has made its own implementation of this model.
Now that I have understood the Actor Model I can have a look to the actor model Akka implementation.



  • Actor and Actor-1 communicate exclusively by exchanging messages asynchronously which are placed into the recipient’s MailBox.
  • Actor and Actor 1 should avoid hogging resources.
  • Message SHOULD NOT be mutable.

ONE important thing from the official documentation:

The only meaningful way for a sender to know whether an interaction was successful is by receiving a business-level acknowledgement message, which is not something Akka could make up on its own (neither are we writing a “do what I mean” framework nor would you want us to).

So as we can see this is the real concept of encapsulation. Every thing happens inside the actor and if you want to delegate a task then It send a message to the actor and keep working. For that reason you ought granulate every task in actor as simple as possible and you should have at the end  that each actor processing be as simple as possible.
Split up the task and delegate it until they become small enough to be handle in One piece!


fig 1.3

As show in fig 1.3 when you invoke the ActorSystem there are several actors that have already been created.
Actor1 is a Supervisor of Actor1.1 and Actor 1.2.

Create only ONE ActorSystem per application is considered a BestPractice because it is a very heavy object and can be create by different ways:
The ActorSystem created can be in the same context or in any other execution context created by us and declared implicitly.
As we can see in fig 1.3 there are different ways of creating actors:
  • Actors that are children of user "guardian" are created by: system.actorOf and in this case  I use to create not many of this kind of actors due to those actors will be the own root actor of my app.
  • Actor that will be child of my own actors(created by us) are created by: context.actorOf , the context is an ActorContext implicit val that there is in the Actor trait.
The ActorContext exposes contextual info for the Actor:
  • self()
  • sender()
  • watch(): used for track actor activities and know when it stopped. Expected a "Terminated"
  • unwatch()
  • actorOf() 
  • become(): change the actor behavior. We decide what message we processed and how. An actor can start processing some type of message and the change its behavior for any reason.
  • actorSelection(actor path): We can select actor for its path (ref. fig 1.3 user/actor1, user/Actor1/Actor1.2)
When we create actors then we get an ActorRef, this is an inmutable reference and identify the actor until it terminate his life. If an actor restart its ActorRef will change.

Terminate(ActorRef  that is being watched, ref watch).  When it happen the Actor free up its resources.

When we have an ActorRef:
  • ! or tell: fire a message and forget.
  • ? or ask: send a message asynchronously and return a future.  
As best practice we should try to send message via ! or tell. [Explain it]

We indicate below the best way to create and invoke different types of actors:

.............

object BootNotScheduled extends App with ScalaLogger{

  val moviePageBoundaries: List[Int] = Try(List(args(0).toInt, args(1).toInt)) match {
    case Success(expectedList) => expectedList
    case  Failure(e) => log.error("Error with the boundaries of your page numbers,reviews your parameters {}",e.toString)
      System.exit(1)
      Nil
  }

  // This actor will control the whole System ("IoTDaemon_Not_Scheduled")
  val system = ActorSystem(ConstantsObject.NotScheduledIoTDaemon)

// creating ioTAdmin actor  
val ioTAdmin = system.actorOf(IoTAdmin.props, ConstantsObject.NotScheduledIoTDaemonProcessing)
  val filteredAndOrderedList = moviePageBoundaries.toSet.toList.sorted
  val filteredAndOrderedListGamesBoundaries = (filteredAndOrderedList.head to filteredAndOrderedList.last).toList

// Sending a message to ioTAdmin actor
ioTAdmin!ParseUrlFilms(filteredAndOrderedListGamesBoundaries,Option(ioTAdmin))
}
ref. to BootNotScheduled code in my github

Props are config classes to specify options when you create actors. You can find below an snapshot configuring the actor ioTAdmin previously created in the above code:

........

object IoTAdmin {
  case class ParseUrlFilms(listTitles: List[moviePage], actorRef: Option[ActorRef]=None)
  case object ErrorStopActor
  case object StopProcess
  def props: Props = Props(new IoTAdmin)
}

...

override def receive = {
.....

}
ref. to IoTAdmin code in my github

The way how I deal  with the configuration is similar as used to be done in most libraries or framework or even in java language. I read the config info from application.conf but there are several way for do  that you can find it in Akka config information, it does not explain at all how deal with it.

What do you have to consider when deal with configuration files in akka:
  • Akka configuration values. We will use default values for the moment.
  • Where the configuration file should be saved and how name it.   
  • How the configuration files are loaded or read. [related class/interfaces: ConfigFactory, Config
The configuration files follow the HOCON specification and we can find a very simple examples on github that will let us create config files easily.

The main akka config files use to be application.conf and uses to be placed in the "resource" folder.
In our real life we usually need to work in different environments and some time we create our application.conf during the compilation process  other time we include in our specifics configurations depending on the environments in which we are working on. We have created a real world config example in which you can configure  a production(production.conf) or development(development.conf) environment. This is not the focus of this post  so if you want learn how work, setting and manage config file you can go to my post about how generating distributions for different environments.

We already have minimal information  to create an Akka App only using the actor module  anyway you can have a look to my github repository akka-quickstart-scala and check about how install and launching it(try the first option in your terminal[sbt "AkkaSchedulerPoc/runMain com.ldg.BootNotScheduled 1 5")]

We have talked in previous posts in this blog about the akka libraries, specifically about schedulers but in this case we post about  the first steps in akka and its core, the actor model. We gonna see other features in next posts  like:
Router
Dispatcher
Akka Test Kit
Akka HTTP