Vikas Pandya
Vikas Pandya

Reputation: 1988

Lightweight eventing Plain Futures or Akka

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.

Upvotes: 0

Views: 246

Answers (1)

John Landahl
John Landahl

Reputation: 1041

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!"))
  }
}

Upvotes: 2

Related Questions