I'm looking to schedule something to run once per day, and the code I want to run involves making updates to entries in the database. I have managed to schedule the running of some simple code by overriding the onStart method in Global.scala using Akka, as follows
override def onStart(app: Application) = {
Akka.system.scheduler.schedule(0.second, 1.second) {
println("hello!")
}
}
The issue is that I want to do something more complicated than logging here, I want to make updates to the database, so I would want to call some function in a models file (models/SomeTable.scala), but I can't import that code in Global.scala.
It sounds like if I want to do something more complicated like that, I should be using Akka's actor system, but I am far from understanding how that works. I've found documentation for how to create Actors through Akka's documentation, though how to incorporate that into my Play project is unclear. Where do I write this Actor class, and how is that imported (what is Global.scala allowed to have access to..?)? And if I don't need to use actors for this, does anyone have some insight into how imports and such work in this part of a Play project?
Note that this part of the Play framework underwent large changes going from Play version 2.3.* to 2.4.*, so it definitely should not be expected that solutions in 2.4.* would likely work here
The information I've gotten above has come mostly from Play's documentation, along with a bunch of related SO questions:
How to schedule task daily + onStart in Play 2.0.4?
how to write cron job in play framework 2.3
Scheduling delaying of jobs tasks in Play framework 2.x app
Where is the job support in Play 2.0?
Was asynchronous jobs removed from the Play framework? What is a better alternative?
Thanks so much in advance!
First of all you definitely need to read about akka.
But for your specific task you do not need to import anything into Global. You just need to start your worker actor. And this actor can schedule regular action itself. As Template
import akka.actor.{Actor, Cancellable, Props}
import scala.concurrent.duration._
class MyActor extends Actor {
private var cancellable: Option[Cancellable] = None
override def preStart(): Unit = {
super.preStart()
cancellable = Some(
context.system.scheduler.schedule(
1.second,
24.hours,
self,
MyActor.Tick
)(context.dispatcher)
)
}
override def postStop(): Unit = {
cancellable.foreach(_.cancel())
cancellable = None
super.postStop()
}
def receive: Receive = {
case MyActor.Tick =>
// here is the start point for your execution
// NEW CODE WILL BE HERE
}
}
object MyActor {
val Name = "my-actor"
def props = Props(new MyActor)
case object Tick
}
Here you have an actor class. With preStart and postStop (read more about actors lifecycle) where defined and cancelled schedule. Scheduled action is sending Tick message to self (in other words actor will receive each 24 hours Tick message and if receive is defined for Tick, this message will be processed).
So you just need to start you implementation where I placed comment.
From Global you just need to start this action in onStart:
Akka.system.actorOf(MyActor.props, MyActor.Name)
Related
First of all, I am not asking how to unit test an Akka Actor. I know the techniques to do that. My problem is slightly different.
I am developing a Scala program, let's call it the client, that does not use Akka Actors. However, the program uses a library, let's call it the server, whose interface is implemented using an Akka Actor.
Then, through the ask pattern, the client interacts with the server.
// This is the client program
class Client(uri: String) {
implicit val context: ActorSystem = ActorSystem("client-actor-system")
private val mainActor = context.actorSelection(uri)
def connect: Future[SomeClass] = {
implicit val timeout: Timeout = Timeout(5 seconds)
(mainActor ? Connect()).mapTo[CreationResponse]
}
}
Now, I want to write down some unit tests for Client class. Unit testing means to test a class in isolation. Every external dependency should be mocked.
How can I mock the reference to mainActor inside Client class? How can I inject in the actor system a mock actor for mainActor?
Thanks in advance.
I would inject the mainActor actor selection into the client, and create that using Akka TestKits.
Of course, you need an ActorSelection, not an ActorRef. Some solutions for that can be found here:
Giving an ActorPath for a testProbe
Or alternatively, you could make mainActor an ActorRef by sending an Identify message to the ActorSelection.
Have a few use cases as follow.
1)createUser API call is made via front end. Once this call succeeds, meaning data is saved to db successfully, return success to the frond end. API contract ends there between front and backend.
2)Now backend needs to generate and fire CreateUser event which creates user into third party app (for the sake of example we can say it'll createUser into an external entitlement system). This is fully asynchronous and background type process where client is neither aware of it nor waiting for this API's success or failure. But all calls to this CreateUser event must be logged along with it's failure or success for auditing and remediation(in case of failure) purposes.
First approach is that we design Future based async APIs for these async events (rest of the app is uses Futures, async heavily), log incoming events and success/failure of result into db.
Second approach is that we use Akka and have individual actor for these events (e.g. CreateUser is one example). Which may look something like
class CreateUserActor extends Actor {
def receive = {
case CreateUserEvent(user, role) =>
val originalSender = sender
val res = Future {
blocking {
//persist CreateUserEvent to db
SomeService.createUser(user, role)
}
}
res onComplete {
case Success(u) => //persist success to db
case Failure(e) => //persist failure to db
}
}
Third approach Use Akka Persistence so persisting of events can happen out of the box with event sourcing journaling. however second persistence of event's success or failure will be manual(write code for it). Though this third approach may look promising it may not pay off well since now we're relying on Akka persistence for persisting events, second requirement of persisting success/failure of event is still manual, and now have to maintain one more storage(persisted journal etc) so not sure if we're buying much here?
Second approach will require to write persisting code for both cases (incoming events and results of the events).
First approach may not look very promising.
Although it may sound like it I didn't intend to create a question that may sound like "Opinion based" but trying to cater in genuine advise with its pros/cons on the mentioned approaches or anything else that may fit in well here.
FYI: This particular application is a play application running on a play server so using Actors isn't an issue.
Since this is a Play application you could use the Akka event stream to publish events without needing a reference to the backend worker actor.
For example, with the following in actors/Subscriber.scala:
package actors
import akka.actor.Actor
import model._
class Subscriber extends Actor {
context.system.eventStream.subscribe(self, classOf[DomainEvent])
def receive = {
case event: DomainEvent =>
println("Received DomainEvent: " + event)
}
}
... and something like this in model/events.scala:
package model
trait DomainEvent
case class TestEvent(message: String) extends DomainEvent
... your controller could publish a TestEvent like this:
object Application extends Controller {
import akka.actor.Props
import play.libs.Akka
Akka.system.actorOf(Props(classOf[actors.Subscriber])) // Create the backend actor
def index = Action {
Akka.system.eventStream.publish(model.TestEvent("message")) // publish an event
Ok(views.html.index("Hi!"))
}
}
I have a play application where I am using actors that are do some constant work / monitoring.
e.g.
class MyActor extends Actor {
def act() { while(true) { /* work */ } }
}
in my code I start this actor exactly once.
My problem is that whenever play automatically rebuilds the application (due to source changes), it will create a new Actor, but will not get rid of the old actor.
The exact same thing happens if using threads (including daemon threads) instead of actors for the monitoring.
Is there any way to kill the old actors / threads on an automatic rebuild, or alternatively ensure that only a single actor will exist (I've tried making the actor thread an object, but this didn't help anything), other than restarting the application manually (I'm fine automatically with restarting the application on every change)?
Also, is there a better pattern for background monitoring in play (obviously one which will not create non-ending threads).
Thanks
You can define a Global object to listen to application events (Which must be defined in the default package):
import play.api.GlobalSettings
object Global extends GlobalSettings {
override def onStart(application: play.api.Application) {
println("Starting actors")
MyActorSystem
}
override def onStop(application: play.api.Application) {
println("Stopping actors")
MyActorSystem.system.shutdown()
}
}
The stop and start events are triggered when reload happens.
If you are using Play's internal actor system I think you can use this instead:
play.api.libs.concurrent.Akka.system.shutdown()
My app gets a new instance of Something via an API call on a stateless controller. After I do my mission critical stuff (like saving it to my Postgres database and committing the transaction) I would now like to do a bunch of fire-and-forget operations.
In my controller I send the model instance to the post-processor:
import _root_.com.eaio.uuid.UUID
import akka.actor.Props
// ... skip a bunch of code
play.api.libs.concurrent.Akka.system.actorOf(
Props[MySomethingPostprocessorActor],
name = "somethingActor"+new UUID().toString()
) ! something
The MySomethingPostprocessorActor actor looks like this:
class MySomethingPostprocessorActor extends Actor with ActorLogging {
def receive = {
case Something(thing, alpha, beta) => try {
play.api.libs.concurrent.Akka.system.actorOf(
Props[MongoActor],
name = "mongoActor"+new UUID().toString()
) ! Something(thing, alpha, beta)
play.api.libs.concurrent.Akka.system.actorOf(
Props[PubsubActor],
name = "pubsubActor"+new UUID().toString()
) ! Something(thing, alpha, beta)
// ... and so forth
} catch {
case e => {
log.error("MySomethingPostprocessorActor error=[{}]", e)
}
}
}
}
So, here's what I'm not sure about:
I know Actor factories are discouraged as per the warning on this page. My remedy for this is to name each actor instance with a unique string provided by UUID, to get around the your-actor-is-not-unique errors:
play.core.ActionInvoker$$anonfun$receive$1$$anon$1:
Execution exception [[InvalidActorNameException:
actor name somethingActor is not unique!]]
Is there a better way to do the above, i.e. instead of giving everything a unique name? All examples in the Akka docs I encountered give actors a static name, which is a bit misleading.
(any other comments are welcome too, e.g. the if the bundling pattern I use is frowned upon, etc)
As far as I'm aware the name paramater is optional.
This may or may not be the case with Akka + Play (haven't checked). When working with standalone actor systems though, you usually only name an actor when you need that reference for later.
From the sounds of it you're tossing out these instances after using them, so you could probably skip the naming step.
Better yet, you could probably save the overhead of creating each actor instance by just wrapping your operations in Futures and using callbacks if need be: http://doc.akka.io/docs/akka/2.0.3/scala/futures.html
I have a Db of Quartz CronTriggers. I want to port this entire system to an Akka based backend I am architecting currently. I was looking at and thinking about ways this can be done.
For instance, CustomRouteBuilders and other similar stuff. I tried the excellent Quartz-Camel-Akka integration example by Giovani and was quite impressed with it. Now, I have multiple cron triggers in my system with different and user created cron expressions.
How can I program a system of Camel Consumer Actors with such user dependent endpointUri's? Was thinking of many options but could not figure out anything yet.
Please help me in this endeavor. I am also open to other ideas beyond Quartz and Camel. I want to stick to Akka based backend platform. My system consists of user defined jobs that fire at user defined cron formable timings.
Starting from a list of cron expressions (e.g. read from database) you could iterate over the list and start a quartz consumer actor for each element. Here's an example:
import akka.actor.Actor
import akka.actor.Actor._
import akka.camel.CamelServiceManager._
import akka.camel.Consumer
object CronExample {
def main(args: Array[String]) {
val cronExpressions: List[String] = ... // cron expressions read from database
startCamelService
cronExpressions foreach { cronExpression =>
val timerName: String = ... // app-specific timer name for cronExpression
actorOf(new Scheduler(timerName, cronExpression)).start
}
}
class Scheduler(timerName: String, cronExpression: String) extends Actor with Consumer {
def endpointUri = "quartz://%s?cron=%s" format (timerName, cronExpression)
protected def receive = {
case msg => ... // react on timer event
}
}
}