Learn

Learn about latest technology

Build

Unleash your talent and coding!

Share

Let more people use it to improve!
 
Mostrando entradas con la etiqueta scala. Mostrar todas las entradas
Mostrando entradas con la etiqueta scala. Mostrar todas las entradas

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




Generating scala application distribution in akka & play for different environments

martes, 12 de febrero de 2019

I have to much for talk about sbt. I have been using this build tooling for a long time and honestly every time that I have to do something  different I need to check sbt documentation. I’ve been thinking in something like sbt in a nutshell, ha ha. Forget about it!. At the same time too many people think that SBT is confusing, complicated, and opaque  and there are a lot of explanation about why. I won't do that in this article.
My target today: how generate distribution package for different environments and the most important  just in one command line clean + compile + build distribution +specific environment

What we need:
  1. pass parameters to our process indicating what environment do you want to build. 
  2. create a plugin to read the parameters. 
  3. create a task that will let you add to the project the appropriate configuration files before the compilation process. 
  4. create a command that have to package the distribution with the suitable option.
I am going to use sbt native packager  for generate distribution for different environments. You don't need to be familiar with this libraries for understand this post but if you want to generate other distributions different than we have explained here my recommendation is a learning in-depth of it.

How to solve point 1:

The first thing that we need to do is to pass a variable in our building process:

sbt -Dour_system_property_var=value_to_assign

So in our case we need to indicate the environment that we are building for:
I am gonna read this environment and set the proper configuration file that will be added to our jar distributions.

You need to coding what to do, considering the parameters that has been passed. You can take some reference about SBT parameters and Build Environment.

Our next steps :
  1. read variables to indicate what environment we want the generation of the new package distribution.
  2. depending of our parameter we need to indicate what config files we want to use in our compilation process. 
To carry out the aforementioned process we need to create an sbt plugin(BuildEnvPlugin.scala):

 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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import sbt.Keys._
import sbt._
import sbt.plugins.JvmPlugin

/**
  * make call in this way for generate development distro
  * sbt -Denv=dev reload clean compile stage
  *
  * make call in this way for generate production distro
  * sbt -Denv=prod reload clean compile stage
  *
  */

/** sets the build environment */
object BuildEnvPlugin extends AutoPlugin {

  // make sure it triggers automatically
  override def trigger = AllRequirements
  override def requires = JvmPlugin

  object autoImport {
    object BuildEnv extends Enumeration {
      val Production, Test, Development = Value
    }
    val buildEnv = settingKey[BuildEnv.Value]("the current build environment")
  }
  import autoImport._

  override def projectSettings: Seq[Setting[_]] = Seq(
    buildEnv := {
      sys.props.get("env")
        .orElse(sys.env.get("BUILD_ENV"))
        .flatMap {
          case "prod" => Some(BuildEnv.Production)
          case "test" => Some(BuildEnv.Test)
          case "dev" => Some(BuildEnv.Development)
          case unkown => None
        }
        .getOrElse(BuildEnv.Development)
    },
    // message indicating in what environment you are building on
    onLoadMessage := {
      val defaultMessage = onLoadMessage.value
      val env = buildEnv.value
      s"""|$defaultMessage
          |Running in build environment: $env""".stripMargin
    }
  )
}
code 1.0

The plugin code above return some build environment that need to be read for any other process.  In a first solution we are going to solve this problem in the main build.sbt file.

In our main build.sbt file (snapshot of code below) depending of the environment selected we are going to copy the proper configuration file to conf/application.conf configuration file  @see line 9 in code below, code 1.1, pay attention that buildEnv.value in line 4 is created/loaded in our customized sbt plugin (code above, code 1.0)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
.............

mappings in Universal += {
  val confFile = buildEnv.value match {
    case BuildEnv.Development => "development.conf"
    case BuildEnv.Test => "test.conf"
    case BuildEnv.Production => "production.conf"
  }
  ((resourceDirectory in Compile).value / confFile) -> "conf/application.conf"
}

.............
code 1.1

Once that you have selected the environment we need to copy all suitable configuration files, afterwards we need to add this code to a task.
Just in this point can pass parameters to our process, indicating what environment we want to build, we have code a plugin than can read parameters. We need to create a command as simple as possible CommandScalaPlay.scala, it will let us to execute in one line reload + clean + compile + tgz distribution of our project.

 1
 2
 4
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import sbt._

object CommandScalaPlay {

/** https://www.scala-sbt.org/sbt-native-packager/gettingstarted.html#native-tools */
  // A simple, multiple-argument command that prints "Hi" followed by the arguments.
  // Again, it leaves the current state unchanged.
  // launching from console a production building:  sbt -Denv=prod buildAll
  def buildAll = Command.args("buildAll", "<name>") { (state, args) =>
    println("buildAll command generating tgz in Universal" + args.mkString(" "))
    "reload"::"clean"::"compile"::"universal:packageZipTarball"::
    state
  }
}
code 1.2

In the above code in code 1.2 we have create a very simple command that   reload + clean + compile + tgz distribution of our project in line 11. You can glance over sbt-native-packager output format in universal if  you are interested in other output format different than tgz.

We need to add the command create above in code 1.3 in our build.sbt main file. So in code below we add the command @see line 11 in code below, code 1.3.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
lazy val commonSettings = Seq(
   name:= """sport-stats""",
   organization := "com.mojitoverdeintw",
   version := "1.0",
   scalaVersion := "2.11.7"
 )
................

settings(commonSettings,
    resourceDirectory in Compile := baseDirectory.value / "conf",
    commands ++= Seq(buildAll))
................
code 1.3

In code above we say to the compiler that our resource directory will be /conf @see line 10 in code above, code 1.3. It shouldn't be necessary because resource directory( resourceDirectory in sbt) in Scala apps sbt resourceDirectory point to src/main/resources but in play framework should be point to /conf.

If you want to create an specific distribution:

go to your HOME_PROJECT and then:
  1. a tgz for production env sbt -Denv=prod buildAll
  2. a tgz for development env sbt -Denv=dev buildAll
  3. a universal for development env sbt -Denv=dev stage
  4. a universal for production env sbt -Denv=dev stage
If you want to implement the above scenario in your own project you need take a look at the following points:
  1. sbt version: in the above scenario is 0.13.11,  reference file: build.properties in my github repository.
  2. plugins.sbt(in my github repository): pay attention to this line: addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.3.2") in my github repository.
  3. build.sbt(in my github repository): Pay attention to this file, mainly about code 1.1 y code 1.4 below in this post.
Take a look about image below where should be the aforementioned files (CommandScalaPlay.scalaBuildEnvPlugin.scalaplugins.sbt)



                                         fig 1.1

Remember that in our configuration folder(in playframework) /conf should be all configuration files that we want in different environments during the distro generation process so at the end one of those files will be our application.conf configuration file. 

In other scenario Instead of create the application.conf file in our main build.sbt file, I reckon that it should be done in code because build.sbt should be as clean as possible. 


                                          fig 1.2


 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
28
29
30
31
32
import sbt._
import sbt.Keys._
import sbt.plugins.JvmPlugin

/**
  * make call in this way for generate development distro
  * sbt -Denv=dev reload clean compile stage
  *
  * make call in this way for generate production distro
  * sbt -Denv=prod reload clean compile stage
  *
  */

/** sets the build environment */
object BuildEnvPlugin extends AutoPlugin {

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

  lazy val configfilegeneratorTask = Def.task {
    val confFile = buildEnv.value match {
      case BuildEnv.Development => "development.conf"
      case BuildEnv.Test => "test.conf"
      case BuildEnv.Stage => "stage.conf"
      case BuildEnv.Production => "production.conf"
    }
    val filesrc = (resourceDirectory in Compile).value / confFile
    val file = (resourceManaged in Compile).value / "application.conf"
    IO.copyFile(filesrc,file)
    Seq(file)
  }
.....................
}
code 1.4

Pay special attention to the task definition configfilegeneratorTask in line 19  in above code(code 1.4) in BuildEnvPlugin.scala(in my github repository)  and then modify the build.sbt file. See the code below and changes that have to be done in our main build.sbt(in my github repository).


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
...................

lazy val root = (project in file(".")).
  aggregate(internetOfThings).
  aggregate(AkkaSchedulerPoc).
  settings(commonSettings,commands ++= Seq(buildAll))

lazy val AkkaSchedulerPoc = (project in file("modules/AkkaScheduler")).
  settings(commonSettings,libraryDependencies ++= Seq(
    "com.enragedginger" %% "akka-quartz-scheduler" % "1.6.1-akka-2.5.x"
 ),resourceGenerators in Compile += configfilegenerator)

...................
code 1.5

Have a look in above code(code 1.5) line 11, here we're adding our task configfilegenerator in our sbt compilation process. You can have a look to this files: build.properties, plugins.sbt, build.sbt

The reference about the last scenario is hosted in other project different than the first scenario but

Remember that plugin and task should be under root project folder. (fig 1.1 above in our post)

Remember that in our configuration folder (in akka) /resource folder  /conf should be all configuration files that we want in different environments during the distro creation process so at the end one of those files will be our application.conf configuration file. 



                                                 fig 1.3
                                 

You need to keep in mind when you are working with autoplugin, when you create task o the other object that execute any processes in an specific phase that you could face some problems about initialization process because some setting are loaded twice. So the sbt initialization could be a useful reading.
In next posts I will explain through code other important implementation when we are working with sbt.

There are different ways to generate distributions in different environments, SBT has many other solutions, but in my opinion they are specific to each file and not for a complete configuration like (log specification file + application configuration file + other properties or metadata file that can change when we change environment)

In this Post we show you examples in Playframework and Akka but how to solve if you want to generate any implementation or distribution without any plugins so you can choose the options that SBT give you:

  • sbt -Dconfig.file=<Path-to-my-specific-config-file>/my-environment-conf-file.conf other-phases 

An example about the aforementioned statement:

     sbt -Dconfig.file=/home/myusr/development.conf reload clean compile stage 

In the same way you can use -Dconfig.resource so in this case you don’t need to specify the path to the file. Sbt will try to find out in the resource directory.

You can do the same with logging configuration so in the same way:

  • sbt -Dlogger.file  <Path-to-my-specific-logger-config-file>/my-environment-logger-conf-file.conf  

or like in config.resource you can use -Dlogger.resource  and in this case you don’t need to specify the path to the log configuration file 'cos the file will be loaded from the classpath.

There are some interesting links in Sbt explaining how deal with distro generation process in different environments :

  1. Specifying different configurations files. 
  2. Specifying different loggings configurations files. 

Something to keep in mind: to use configurations files properly pay attention to HOCON (Human-Optimized Config Object Notation) and how it work. It could be very helpful. We can tackle this subject in next posts

We agreed that SBT is not easy, it is a powerful tool but it is not easy. Perhaps for that reason developer don't use it if they can use any other build tooling. Any way I will be posting some problems that we face when we are coding with scala and SBT make easier our work.

Scheduling in Akka with Quartz - a wise solution

lunes, 24 de septiembre de 2018

My problem arise when I needed to execute several task following specific schedule (day/time) indefinitely for long term. This tasks should have different patterns and the schedule will vary definitely in time, the task that we execute today will be different than the task that I am going to execute next week indeed and the same with its schedule.

So I am going to tell you my environment and what I want:
  • A process like linux cron services for running commands following pre-determined schedule.
  • Objects that should be able to process configuration files that contain lists of command lines and when its should be invoked.
  • Objects that should be able to process config files. This config files contain lists of command and when that can be invoked(in time).
  • Some of the aforementioned configurations files must be modified dynamically. That means without stop our application.
Why do not use linux cron + crontable and execute shell scripting files:
  1. For its configuration. 
  2. For the scalability that we need.
  3. For the shell scripting complexity that we ought need (in my real life I used to need data base connections, parse thousands urls, parallel processing on net, etc).
  4. It is our OS configuration task.
All of this in an environment where we need an intensive use of concurrency. So I have to deal with this scenario but akka libraries do not have solution for it. So the are several options on the market, some of them:
  1. Apache Camel Timer
  2. Quartz
  3. Akka-Quartz Scheduler
So in my case I going to use the last one, Akka-Quartz Scheduler, there are several reason, Apache Camel in my opinion is too complicated for just for use his Timer and related to Quartz have the same problem and too oriented to java community, so every kind of listener has to be implemented and we need to work in an akka environment.

I will not tell you here what is better o worst option for my “akka cron environment”. Scheduler and Timers are a very complicated aspects in programming so if you want a right opinion you will need a deep benchmarking between the three of them. It is not the intention of this document.

What are we going to do in our example:
  1. We need to execute several task following specific schedule (day/time) indefinitely until something goes wrong.
  2. We should  change the aforementioned schedule, if we need, for any other. All without stop any of our actors that are busy executing our task.
It is up to you don't change the scheduler with PAST dates.I do not make any validation about the date that you configure in your schedule.

As  Akka-Quartz Scheduler explain, its goal is to provide Akka with a scheduling system that is closer to what one would expect for Cron type jobs.

This is the example that I bring to readers today:

We have a platform whose target is to collect information from a web page that publishes everything related to movies. At the same time I know that every month is published the information about when(in the time) will be added new pages with the info related to new movies. All our code is based on AkkaScheduler module on my github, it is a multi-module project so you can follow the instruction indicated in the repository if you want to deploy it. 

Our project has a very  important aspect:

Configuration files: I have 2 configuration files.
One of them will indicate me that every month I have to do something, this configuration is internal and will be in an internal file. In our case will be in the akka configuration file(application.conf) on my github :

1
2
3
4
5
6
7
8
9
  quartz {
   defaultTimezone = "Europe/London"
   schedules {
    moviepages {
     description = "A cron job that fires off every month"
     expression = "0 30 2 2 * ? *"
    }
   }
  }
code 1.0

See this reference to the CronExpression. Because the info is published every first day in the month I  will check at the beginning of the second day every month. So this is an internal configuration ref: code 1.0 because it never change(I have to review every month for a schedule about the pages related to new films that will be added or updated)

The Second of them will indicate me when will be updated each page that has the information, during the whole month. This will be an external configuration file that indicate when will be updated or added any new page throughout the month.  So that day that the page be updated or added our actor will collect information about it. Every month this external file has to be changed with another new schedule.
An example of my external file (cronmoviepages.confthat you can find on my github is below:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
## https://github.com/lightbend/config/blob/master/HOCON.md
## cronexpresssion = "Seconds Minutes Hours Day-of-month Month Day-of-Week Year(Optional)"

schedule {
  defaultTimezone = "Europe/London"
  moviepagemejorenvo = [
    {
      cronexpresssion = "0 4 2 20 9 ? *"
      moviepage = "40"
    }
    {
      cronexpresssion = "0 4 2 20 9 ? *"
      moviepage = "41"
    }
  ]
}
code 1.1

In code 1.1 cronexpression means when the actor has to update the associate page from the movie website. Internally the software will group all moviepage with the same cronexpression and will fire the jobs with each common group.

We have two main cores:
  • For initialize the process BootNotScheduled . In this case we know what pages we want to update so we do not use the schedule.
  • For start the schedule process BootScheduled . This is main program that fire the scheduler. 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
object BootScheduled extends App {
  //https://github.com/lambdista/config
  val system = ActorSystem(ConstantsObject.ScheduledIoTDaemon)
  // This actor will control the whole System ("IoTDaemon_Scheduled")
  val daemonScheduled = system.actorOf(IoTAdmin.props, ConstantsObject.ScheduledIoTDaemonProcessing)
  // This actor will control the reScheduling about time table for update new pages with films in original version
  val reeschedule = system.actorOf(ReSchedulingJob.props, ConstantsObject.DaemonReShedulingVoMoviePages)
  //Use system's dispatcher as ExecutionContext
  //QuartzSchedulerExtension is scoped to that ActorSystem and there will only ever be one instance of it per ActorSystem
  QuartzSchedulerExtension(system).schedule("moviepages", reeschedule, FireSchedule(daemonScheduled))
}
code 1.3

In the previous code 1.3 on line 10 It will use the internal configuration from our application.conf ref. code 1.0. At the same time this line is responsible of every second day of the month at 2.30 am fire a job that will read the schedule a new scheduler  ref. code 1.1(cronmoviepages.conf), the external file that can be read periodically and it indicates what jobs be re-scheduled every time with the new schedule.

 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
.....................

      cronExpreesionMatches.foreach(
        cronExpreesionMatch => {
          val (cronExpreesion, listOfMoviePages) = cronExpreesionMatch
          log.info(
            "Programming Schedule for cronexpression: {} including matches: {}",
            cronExpreesion,listOfMoviePages.mkString("-")
          )
          val headList = listOfMoviePages.head

          // TODO it is important to kill all Scheduled jobs that has been created ONCE time that the work has done

          /** This code generate a warning because the reschedule job never exist
            * any more because headList used for named it never is the same*/
          QuartzSchedulerExtension(system).rescheduleJob(
            s"Movie-Page-Scheduler$headList",
            scheduledDaemon,
            ParseUrlFilms(listOfMoviePages),
            Option("Scheduling "), cronExpreesion, None, defaultTimezone)
        }
      )
      log.info("schedule get new MoviePages")
  }

.....................
code 1.4

In the previous code 1.4 on line 16 we re-schedule an actor (IoTAdmin) to be fire following the external configuration and then it will launch concurrently so many actors(ProcessMoviePage) as many pages need to be updated. You can appreciate that in the code below.

 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
........

class IoTAdmin extends Actor with ActorLogging with MessageToTargetActors{
  override def preStart(): Unit = log.info("Start process in Akka Scheduler Example")
  override def postStop(): Unit = log.info("Stop process in Akka Schedule Example")
  // TODO checking perfromance: http://docs.scala-lang.org/overviews/collections/performance-characteristics.html

  var watched = Map.empty[ActorRef, Int]

  override def receive = {

    case ParseUrlFilms(urlPageNunmList, optActorRef) =>

      urlPageNunmList.foreach(
              urlpagenumber => {
                val currentActorRef: ActorRef = context.actorOf(ProcessMoviePage.props)
                watched += currentActorRef -> urlpagenumber
                // watcher for every actor that is created 'cause the actor need to know when the process have finished
                context.watch(currentActorRef)
                // TODO urlspatterns<=varconf
                val processUrlFilmMessage = ProccessPage(
                  s"http://mejorenvo.com/p${urlpagenumber}.html",
                  optActorRef.fold(self)(ref=>ref)
                )
                sendParserUrlMessage(currentActorRef, processUrlFilmMessage)
              })
.............
code 1.5

Every specific day that was configured in cronmoviepages.conf file the IoTAdmin actor will receive a ParseUrlFilms message to process the new page that should be updated.

This post and the project can be a base or skeleton for you if you want to create a process with the following specifications:
  • If you need to execute scheduled task and these tasks occur at a specific moment in time and not need to be executed periodically.
  • If you  need to execute several task following a customizable schedule (day/time), indefinitely until something goes wrong.

This is the idea of our cron but more in deep because some time we need to do more complex thing, external to our OS.
I have used Akka-Quartz Scheduler with docker container and it works pretty well. I have NOT tested the use of this libraries in an Akka Clustering Environment with the complexity that these kind of implementations entail. You can get access to Akka Documentation about  to try of configure seed nodes on any PaaS and run it. You can do it manually but when you are working on a PaaS you need to do it automatically.  The explanation in Akka Library documentation and specifically the reference to Cluster Bootstrap was not working at the time of writing this article. I will try to explain and implement it in next post.

Testing RESTful PlayFramework applications

miércoles, 30 de mayo de 2018

As was  argued by Robert C. Martin in his Clean Code bible, there are several aspects that we have to pay attention when we design our tests:
       - Minimize the number of assert per concept.
       - Test just one concept per test function.
       - Test should not depend on each other. 
       - Test should run in any environment. 
Test should pass or fail BUT you should not make process or any other thing for check if the Test was OK or failed.
Write the TEST first OR with the code, NOT after it be running in a production environment.

I am going to talk about Test Implementation in Scala and more specific in Scala  Playframework applications. If you come from Java programming language perhaps the more easy way is by ScalaTest - FlatSpec, it is a good starting point.

So when we are trying UNIT TEST in Play Framework, our minimal tests should include the followings artifacts:
  • Controller
  • Actions
  • Routes
  • Our services or functionalities, obviously
For make the previous topics more easy I have some IMPORTANT tips:
  1. Encapsulate your operations in services.
  2. Inject the classes that manage the above services.
  3. Create the relationship Class - Trait. It will let you create binding in your tests with Guice in a more easy way and at the same time get the benefits already known of this programming practice.
The main ideas are:
  • Mock services that you don't want to test. Your tests must be focused as much as you can in the functionalities that you want try.
  • Test the Controller.
  • Test the actions: When we talk about test actions that means test our action builders,  test the definitions that process every path in each request. A good idea is that action builders can process all related with our request as for example content-type. It will let us  filter for an expected Content-Type request and if it isn't what we expect stop the processing.
  • Test the routes: It is important to know that all routes defined for us are working properly or at least can be reached by the proper path.
  • Test any other Function or Service related with HTTP request. For example methods/functions related with content negotiation normally need make use of HTTP Header and in that case we will need set the header in a Fake-request.
  • Test services functionalities. I  won’t include anything related with HTTP request here. Just our own functionalities.
In an "Ideal Hello World Play Framework application" EVERY THINGS is very simple BUT the problems arise in Real World application with escenarios like that:
  • Multimodule applications.
  • Several route files.
  • Several bindings class that are injected in Singleton Class.
  • Class referencing configurations files.
  • And for example you have bindings with Class that inject other Singleton class and that Class at the same time have some references to configuration files in your Project. 
I will talk here about testing problems that are not clearly treated in Play documentation and how tackle it. When you are in real life with play framework applications is when you understand how tedious is mock a binding in Guice when you trying to create Fake apps for Testing.
It is more easy MockitoSugar in this context and could be better if when you mock any component  in Guice we could have the MockitoSugar concept instead of having to create a Well Mocked Object and binding it when you try to make an App via Guice Builder.

A design made for an easy/smart test:

I will not tell here why is so important dependency injection, you can find that information in every where even in playframework documentation.

In the following example I will show a controller that manage the actions:

 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
28
29
30
31
32
33
class FootballLeagueController @Inject()(action: DefaultControllerComponents, services: TDataServices) extends BaseController with ContentNegotiation {

  /**
    * Best way, using a wrapper for an action that process a POST with a JSON 
    * in the request.
    *
    * @see utilities.DefaultControllerComponents.jsonActionBuilder a reference 
    *      to JsonActionBuilder a builder of actions that process POST request
    * @return specific Result when every things is Ok so we send the status 
    *         and the comment with the specific json that show the result
    */

    def insertMatchWithCustomized = action.jsonActionBuilder{ implicit request =>
    val matchGame: Match = request.body.asJson.get.as[Match]
      processContentNegotiationForJson[Match](matchGame)
  }

// ..............

  def insertMatchGeneric = JsonAction[Match](matchReads){ implicit request =>
    val matchGame: Match = request.body.asJson.get.as[Match]
    processContentNegotiationForJson[Match](matchGame)
  }

// ..........

  def getMatchGame = action.defaultActionBuilder { implicit request =>
    val dataResults:Seq[Match] = services.modelOfMatchFootball("football.txt")
    proccessContentNegotiation[Match](dataResults)
  }

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

}
code_example 1 ref. source code Controller

Some of my recommendations for  the real life Controllers:
  • I mostly need a custom action so inject a component [ref. code_example 1 line 1] in the previous snapshot of code [action: DefaultControllerComponents]) and this CUSTOM action will simplify the processing of your requests in Play and at the same time this design will make easy your test, something very important in our TDD process as we will see later.
  • Encapsulate the operations that must be done in your actions in services and INJECT it in your controller([ref. code_example 1 line 1[services: TDataServices]), some tips here: Inject a trait and bind that trait to a concrete class both things are truly important.  If any service include for example any customizable object like a database connection do NOT inject at this level do it in the concrete class. 
In our Controller [ref. code_example 1we are going to Test first the Controller:

 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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/**
  * Created by ldipotet on 23/09/17
  */
package com.ldg.play.test


import com.ldg.basecontrollers.{DefaultActionBuilder, DefaultControllerComponents, JsonActionBuilder}
.......
import com.ldg.model.Match
import com.ldg.play.baseclass.UnitSpec
import controllers.FootballLeagueController
import org.mockito.Mockito._
import org.scalatest.mock.MockitoSugar
import play.api.test.FakeRequest
import play.api.test.Helpers._
.......
import services.TDataServices


class FootballControllerSpec extends UnitSpec with MockitoSugar {

  val mockDataServices = mock[TDataServices]
  val mockDefaultControllerComponents = mock[DefaultControllerComponents]
  val mockActionBuilder = new JsonActionBuilder()
  val mockDefaultActionBuilder = new DefaultActionBuilder()
........
  val TestDefaultControllerComponents: DefaultControllerComponents = DefaultControllerComponents(mockDefaultActionBuilder,mockActionBuilder,/*messagesApi,*/langs)
  val TestFootballleagueController = new FootballLeagueController(TestDefaultControllerComponents,mockDataServices)

  /**
    *
    * Testing right response for acceptance of application/header
    * Request: plain text
    * Response: a Json
    *
    */

  "Request /GET/ with Content-Type:text/plain and application/json" should
    "return a json file Response with a 200 Code" in {

      when(mockDataServices.modelOfMatchFootball("football.txt")) thenReturn Seq(matchGame)
      val request = FakeRequest(GET, "/football/matchs")
        .withHeaders(("Accept","application/json"),("Content-Type","text/plain"))
      val result = TestFootballleagueController.getMatchGame(request)
      val resultMatchGame: Match = (contentAsJson(result) \ "message" \ 0).as[Match]
      status(result) shouldBe OK
      resultMatchGame.homeTeam.name should equal(matchGame.homeTeam.name)
      resultMatchGame.homeTeam.goals should equal(matchGame.homeTeam.goals)

    }

  /**
    *
    * Testing right response for acceptance of application/header
    * Testing  template work fine: Result of a mocked template shoulBe equal to Res
    * Request: plain text
    * Response: a CSV file
    *
    */

  "Request /GET/ with Content-Type:text/plain and txt/csv" should "return a csv file Response with a 200 Code" in {
    when(mockDataServices.modelOfMatchFootball("football.txt")) thenReturn Seq(matchGame)
    val request = FakeRequest(GET, "/football/matchs").withHeaders(("Accept","text/csv"),("Content-Type","text/plain"))    val result = TestFootballleagueController.getMatchGame(request)
    val content = views.csv.football(Seq(matchGame))
    val templateContent: String = contentAsString(content)
    val resultContent: String = contentAsString(result)
    status(result) shouldBe OK
    templateContent should equal(resultContent)
  }

  "Request /GET with Content-Type:text/plain and WRONG Accept: image/jpeg" should
    "return a json file Response with a 406 Code" in {
    val result = TestFootballleagueController.getMatchGame      .apply(FakeRequest(GET, "/").withHeaders(("Accept","image/jpeg"),("Content-Type","text/plain")))
    status(result) shouldBe NOT_ACCEPTABLE
  }
}
code_example 2 ref. source code ControllerSpec 

So if I am planning to test my Controller and if at the same time it is being injected by several component, the first thing that I need to do is give value to those components and because our target here are NOT the components I will mock them! [ref. code_example 2 line 22 - 25]:

  val mockDataServices = mock[TDataServices]
  val mockDefaultControllerComponents = mock[DefaultControllerComponents]
  val mockActionBuilder = new JsonActionBuilder()
  val mockDefaultActionBuilder = new DefaultActionBuilder()

TDataServices is a trait so we need binding it to a Concrete class, that is a very good practice. As the play specification indicates: by default Play will load any class called Module that is defined in the root package (the "app" directory) or you can define them in any place and indicate where to find it in the play configuration file(application.conf) under play.modules configuration value.

..............
class Module extends AbstractModule {
   ...................
   bind(classOf[TDataServices]).to(classOf[DataServices])
      .asEagerSingleton()
  }
}
code_example 3 ref. source code bindings

You can find more information in Play Documentation about custom and eager bindings. You should pay attention about this, it is important for several practices and in our case we will see the benefits of it in Testing.

I recommend Test with Guice only when we do not have any other choice. That is why if I need to inject a data base connection, for example, I wouldn't do it in the Controller it is better do it in the service class indeed.

Our first Test Testing Controllers begin in [ref. code_example 2  line 38 - 48] :

I need to simulate a behaviour so if any process call  services.modelOfMatchFootball[ref.code_example 1 line 27] I will return Seq(matchGame):
when(mockDataServices.modelOfMatchFootball("football.txt")) thenReturn Seq(matchGame)
in my FootballControllerSpec.
In the same way I will mock the controller because I want to inject all mocked component too and test the flow of the controller. Remember that we are in [ref. code_example 2  line 38 - 48] so I have a Fake request , something important is that we can add to this request a header, body(json, text, xml), cookies and whatever that any request has. Test will execute Controller but with mocked components and will process everything and return a response in the same way:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
.........................      
when(mockDataServices.modelOfMatchFootball("football.txt")) thenReturn Seq(matchGame)
      val request = FakeRequest(GET, "/football/matchs")
        .withHeaders(("Accept","application/json"),("Content-Type","text/plain"))
      val result = TestFootballleagueController.getMatchGame(request)
      val resultMatchGame: Match = (contentAsJson(result) \ "message" \ 0).as[Match]
      status(result) shouldBe OK
      resultMatchGame.homeTeam.name should equal(matchGame.homeTeam.name)
      resultMatchGame.homeTeam.goals should equal(matchGame.homeTeam.goals)
..........................

If  TestFootballleagueController.getMatchGame method had any parameter then the statement would be TestFootballleagueController.getMatchGame(anyparam)(request)[ref.  line 5 previous code]. In our example I have to deal with content-negotiation so I have added a header easily to my FakeRequest and then we  expect the right processing from my content-negotiation method and the right response.
It is important to know that FakeRequest(GET, "/football/matchs") is the same that FakeRequest(GET, "/"), it has nothing to do with the routes defined in the conf/routes file.

In our Controller [ref.code_example 1we are going to Test now the Actions:

 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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package com.ldg.play.test

import akka.stream.Materializer
import com.ldg.basecontrollers.{BaseController, DefaultActionBuilder, JsonActionBuilder}
import com.ldg.implicitconversions.ImplicitConversions.matchReads
import com.ldg.model.Match
import com.ldg.play.baseclass.UnitSpec
import play.api.test.FakeRequest
import play.api.libs.json._
import play.api.test.Helpers._
import play.api.http.Status.OK
import play.api.inject.guice.GuiceApplicationBuilder
import play.api.mvc.Results.Status
import scala.io.Source

class FootballActionsSpec extends UnitSpec {

  val jsonActionBuilder = new JsonActionBuilder()
  val defaultActionBuilder = new DefaultActionBuilder()
  val jsonGenericAction = new BaseController().JsonAction[Match](matchReads)

  val rightMatchJson = Source.fromURL(getClass.getResource("/rightmatch.json")).getLines.mkString
  val wrongMatchJson = Source.fromURL(getClass.getResource("/wrongmatch.json")).getLines.mkString

  implicit lazy val app: play.api.Application = new GuiceApplicationBuilder().configure().build()
  implicit lazy val materializer: Materializer = app.materializer

  /**
    * Test JsonActionBuilder:
    *
    * validate: content-type
    *           jsonBody must be specific Model
    *
    * @see com.ldg.basecontrollers.JsonActionBuilder
    *
    * Request: application/json
    *
    */

  "JsonActionBuilder with Content-Type:application/json and a right Json body" should "return a 200 Code" in {
    val request = FakeRequest(POST, "/")
      .withJsonBody(Json.parse(rightMatchJson))
      .withHeaders(("Content-Type", "application/json"))

    def action = jsonActionBuilder{ implicit request =>
      new Status(OK)
    }
    val result = call(action, request)
    status(result) shouldBe OK
  }

.......

  "JsonAction with Content-Type:application/json and a wrong Json body" should "return a 400 Code" in {
    val request = FakeRequest(POST, "/")
      .withJsonBody(Json.parse(wrongMatchJson))
      .withHeaders(("Content-Type", "application/json"))

    def action = jsonGenericAction{ implicit request =>
      new Status(OK)
    }
    val result = call(action, request)
    status(result) shouldBe BAD_REQUEST
  }

.......

  "DefaultActionBuilder with Content-Type:text/plain and a right Json body" should "return a 200 Code" in {
    val request = FakeRequest(GET, "/").withHeaders(("Accept","application/json"),("Content-Type", "text/plain"))

    def action = defaultActionBuilder{ implicit request =>
      new Status(OK)
    }
    val result = call(action, request)
    status(result) shouldBe OK
  }

.......

}
code_example 4 ref. source code ActionsSpec

We are going to highlight this import [ref. code_example 4  line 10]:
  • import play.api.test.Helpers._
The previous import will let call an action with an specific request(GET/POST....). An example of this call in [ref. code_example 4  line 48]:
  • call(action, request)
But the previous call need an implicit value, an instance of a Materializer so the best way for build it if we can not get an instance of our application is through Guice see [ref. code_example 4  line 25 - 26].
I am testing the Actions so in my case I will test only Action/ActionBuilder and some aspects related with the request. I won't test here the service that is executed under an specific action. Take a look about [ref. code_example 4  line 42] about our JsonBody in our FakeRequest.
It is not the objective of this post but you could take a look to JsonActionBuilder and DefaultActionBuilder [ref. code_example 4  line 19-20]

In our Controller [ref.code_example 1we are going to Test now the Routes:

 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
28
package com.ldg.play.test


import apirest.Routes
import com.ldg.play.baseclass.UnitSpec
import services.{MockTDataServices, TDataServices}

import play.api.inject.bind
import play.api.test.FakeRequest
import play.api.test.Helpers._
import play.api.inject.guice.GuiceApplicationBuilder

class FootballRoutesSpec extends UnitSpec {

  val app = new GuiceApplicationBuilder()
    .overrides(bind[TDataServices].to[MockTDataServices])
    .configure("play.http.router" -> classOf[Routes].getName)
    .build()

 // implicit lazy val materializer: Materializer = app.materializer

   "Request /GET/football/PRML/matchs with Content-Type:text/plain and application/json" should    "return a json file Response with a 200 Code" in {
    val Some(result) = route(app, FakeRequest(GET, "/football/matchs")      .withHeaders(("Accept", "application/json"),("Content-Type", "text/plain")))
    status(result) shouldBe OK
  }
}
code_example 5 ref. source code RoutesSpec

This aspect is not clear in PlayFramework documentations. First of all I need to create a Fake application with the same skeleton that the real so I need to do the following:
  1. Create a fake app
  2. Mock all service that I am going to use like in my real app
  3. Create my route file
The previous 3 points are solved in  [ref. code_example 5 line 15 - line 18]:
  •  [ref. code_example 5 line 15]: We create a mock using a binding. It was one of the important thing that explain at the beginning. Mocks implemented in Guice are completely different at Mockito. In Guice you will need to mock the whole object. So what we are doing here is overriding our binding with bindings to my mocked object. You can take a look of my mocked object MockTDataServices but in general you have to give fixed values in your mocked object to any definitions in your concrete class.
  • [ref. code_example 5 line 16]: I am indicating here to my Fake app the route file that I want to use. The way to indicate to my fake app the route file is overriding the route file in our case  play.http.router -> the router class indicate the route file of our app(the routes that we want to test
I have to import the auto-generated/compiled scala class Routes. PlayFramework constructs a Route class for each configuration route file. In our Routes class generated there is an important method:

def routes: PartialFunction[RequestHeader, Handler]

The aforementioned method can give us all route in our project. So if I want to test the routes of my project then a good idea should be make every request with his specific path and test if it is working properly.

Any way this post is just the tip of the iceberg. My advice is that take a look in the test module of playframework source code that is the case ScalaFunctionalTestSpec because the documentation in this point is not pretty well on playframework documentation.

So in examples like the next snapshot of code in framework documentation


1
2
3
4
5
6
7
8
"respond to the index Action" in new App(applicationWithRouter) {
  val Some(result) = route(app, FakeRequest(GET_REQUEST, "/Bob"))

  status(result) mustEqual OK
  contentType(result) mustEqual Some("text/html")
  charset(result) mustEqual Some("utf-8")
  contentAsString(result) must include("Hello Bob")
}

They never explain how get applicationWithRouter in line 1 in the above code for instance. The solution:

1
2
3
4
5
6
7
8
  val applicationWithRouter = GuiceApplicationBuilder().appRoutes { app =>
      val Action = app.injector.instanceOf[DefaultActionBuilder]
      ({
        case ("GET", "/Bob") => Action {
          Ok("Hello Bob") as "text/html; charset=utf-8"
        }
      })
    }.build()

Testing is easy and should be an style of programming, perhaps in lightbend the make it just a bit more difficult. Anyway, in my opinion, this play framework is terrific, not your documentation.