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
}
}
}
Related
Let's say I have DAO Actors (CassDaoActor, VerticaDaoActor, etc) that respond to message 'Read'.
First of all, is there a way to express a interface or abstract class that defines the message 'Read' that extending actors should implement?
Now assume it's only at runtime that I could get to know which Actor needs to be created based on the configured db. For example, if configured db is cassandra, I need to create CassDaoActor, etc. This apparently is a typical use case for Factory Method Pattern as we know. I want to understand how can we implement such a thing? Evidently we can't pass "context" around since it looses content outside the scope of the actor.
Please suggest.
What I have tried so far is that I am returning respective props based on the configured db to the actor within which I need to create these actors.
object `package` {
val CASS = "cass"
val VERTICA = "vertica"
def getDAOProps(db: String): Props = db match {
case CASS => CassDaoActor.props
case VERTICA => VerticaDaoActor.props
}
}
// SupervisorActor
val db = configuredDb()
context.actorOf(getDAOProps(db), db)
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)
I am using (learning to) handle websockets in play application.
My controller is using WebSocket.acceptWithActor
def clientWS = WebSocket.acceptWithActor[JsValue, JsValue] { _ =>
upstream => ClientSesssionActor.props(upstream)
}
and all is well except some other "supervisor" actor needs to be able to use context.actorSelection(...) to communicate with all/some of those ClientSessionActors.
But all my ClientSessionActors are created with a path like this one :
[akka://application/system/websockets/ REQ_ID /handler]
Here is the line where WebsocketActorSupervisor creates them :
val webSocketActor = context.watch(context.actorOf(createHandler(self), "handler"))
That is where the "handler" part of the path comes from.
I would like to pass in a specific name for my ClientSessionActor instead of getting "handler".
Overloading the whole call stack with one more parameter seems inelegant: there is WebSocketActor.scala with Connect, WebSocketActorSupervisor(props and constructor), WebSocketsActor receive and then everything inside the WebSocket.scala.
I know I can pass the supervisor reference to the props, but what about the case when the "supervisor" has been restarted and needs to reconnect with his minions.
One more thing, I realize that I might be able to get all the "handler" actors, but there are more than 2 kinds of handlers. Yes I could have them ignore msgs directed at the other groups of handlers but this just feels so redundant sending out 3 times more msgs than I should have to.
Any suggestions ?
James ? :)
Thank you
How about each ClientSesssionActor sends a Register message to supervisor on preStart and store them in eg. val sessions = new HashMap[String, ActorRef].
And then unregister by sending Unregister in postStop
private class WebSocketsActor extends Actor {
import WebSocketsActor._
def receive = {
case c # Connect(requestId, enumerator, iteratee, createHandler) =>
implicit val mt = c.messageType
context.actorOf(WebSocketActorSupervisor.props(enumerator, iteratee, createHandler),
requestId.toString)
}
}
Here is code how play creates actors for handling websockets, it names with requestId.
I have also same question :) why not make it to name with custom names.
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!"))
}
}
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