Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cake pattern w/ akka: Providing implicit actorSystem to several layers

I'm currently baking my first cake pattern, so please bear with me.

I took my working monolithic app and I cutted it into functional layers. The cut looks clean but resulted in two of the layers that depend on an implicit ActorSystem.

I tried to solve this dependency like this:

trait LayerA {
  this: ActorSystemProvider =>
  private implicit val implicitActorSystem = actorSystem
  import implicitActorSystem.dispatcher // implicit execution ctx
  ...
}

... and similarly for LayerX

My assembly class looks like:

class Assembly extends LayerA with LayerB with LayerX with ActorSystemProvider

where ActorSystemProvider simply instantiates the actor system.

This does not work given that the ActorSystem does not exist when the dependencies are resolved and the val's are instantiated, resulting in a NPE. This also looks really ugly and I'm sure there has to be a nicer/easier way to deal with it.

How should I deal with shared implicit dependencies among layers when using the cake pattern, like ActorSystem in this case?

Thanks

like image 338
maasg Avatar asked Jan 30 '14 18:01

maasg


2 Answers

Self types is not a requirement for building a caked architecture, actually i use self types only in cases when a trait is a component of a layer. So when i need to place some implicit into the scope (for example ActorRefFactory for Spray Client) i just mix a trait in :

trait ActorSystemProvider {
  implicit def actorSystem: ActorSystem
}

And on the lowest layer (so called "end of the world") i have the following code structure:

trait ServiceStack
  extends SomeModule
     with SomeModule2
     with SomeModule3 
     with ActorSystemProvider 

object ServiceLauncher extends App with ServiceStack {
  val actorSystem = ActorSystem("ServiceName")
}

It's an oversimplified example (if you want a great example of a real system build on top of a Cake Pattern then you should definitely take a look at the Precog system, example where different modules/layers connects), but not you can mix implicit ActorSystem when you need it.

like image 119
4lex1v Avatar answered Nov 10 '22 10:11

4lex1v


If you can instantiate the vals lazily rather than eagerly, you can make the implicitActorSystem a lazy val instead of a val. So it only gets executed when it is accessed the first time. I think this should solve the problem of NPE. (Another little known interesting fact posted by @ViktorKlang FYI: If the initialization of a lazy val throws an exception, it will attempt to reinitialize the val at next access.)

Another way would be to make each of your methods which need execution context accept an implicit executionContext like:

trait LayerA {
  def getUser(id: Int)(implicit ec: ExecutionContext) = {
    ...
  }
}
like image 26
Sudheer Aedama Avatar answered Nov 10 '22 11:11

Sudheer Aedama