Home Best Practices Typed actors with routing

Typed actors with routing

Author

Date

Category

This is a blog post of our Code Reading Wednesdays from Codacy (http://www.codacy.com): we make code reviews easier and automatic.

A few weeks ago we wrote about typed actors and how we built our architecture around them. This week we are going to explain how we use them with routing to scale our system.

With Typed Actors, like with normal Actors, you have an external API that will delegate method calls asynchronously to a private instance of the implementation. The advantage is that Typed Actors have a static contract and you donโ€™t need to define your own messages, although there are some limitations on what you can do, i.e. you cannot use routing as in normal actors.

With our architecture using typed actors, and rolling back to untyped actors not being an acceptable solution, we decided to invest some time researching for a proper way to achieve typed actors with routing.

Research

After a lot of documentation reading and trial/error we could not find any working solution that could meet our needs, so we started searching for other similar cases on the web.

The problem was already common within the Akka community and we found a lot of suggestions but not a fully working solution.

A common solution was to create a sequence of actors and let them be routed by an untyped actor. As you may think, that would break our main goal of having typed actors and would throw as back to the traditional Akka message system.

This solution is not useless because it solves part of the problem, so we decided to work with it to meet out needs. The next step was to start looking for a way to connect one of our typed actor with the list of actors to route and we found that, even thought a typed actor canโ€™t have routing, it could receive a untyped router.

Solution

The solution is a pretty simple composition of the two options I explained before.

To start we need a group of typed actors, a sequence of the actors you want to route. These are the actors thatโ€™ll do the actual work.

To manage those actors we need to create an untyped actor that routes them, a simple actor with any of the default Akka routers or even with one you define, and then pass the typed actors you created before as workers.

To complete the typed actors router we obviously need a typed actor, so we can have a typed interface to the untyped actor as if we have a single one. This is achieved by creating a typed actor equal to the ones in the sequence, but in this case you pass him the router you created in the second step, and that will have a typed actor set up.

Implementation

Since we use Scala, weโ€™re providing a simplified Scala implementation.

Starting by the typed actors that will be routed:

val actors = (1 to actorCount).map {
    i =>
      TypedActor.get(system).getActorRefFor(TypedActor.get(system).typedActorOf(TypedProps(Reflect(system).actorClassFor(className.get)).withTimeout(timeout)))
  }

Then the untyped actor that will route the previous actors:

val router = system.actorOf(Props.empty.withRouter(SmallestMailboxRouter.create(actors.toIterable.asJava)))

And to finish the typed actor that will be the interface to the routing system:

TypedActor(system).typedActorOf(TypedProps(Reflect(system).actorClassFor(className.get)).withTimeout(timeout), router)

And now a complete example:

123456789101112131415161718

val defaultAkkaTimeout = 60

val defaultNumberOfActors = 10

def getComponentActor[T <: AnyRef](timeout: akka.util.Timeout = Timeout(Duration(defaultAkkaTimeout, SECONDS)))(implicit m: Manifest[T]): T = {

val className = this.classCache.get(m.runtimeClass.getName)

val actorCount = defaultNumberOfActors

val actors = createRouterActors(actorCount,className,timeout)

val router = system.actorOf(Props.empty.withRouter(SmallestMailboxRouter.create(actors.toIterable.asJava)))

TypedActor(system).typedActorOf(TypedProps(Reflect(system).actorClassFor(className.get)).withTimeout(timeout), router)

}

def createRouterActors[T <: AnyRef](actorCount:Int, className:Option[String], timeout:akka.util.Timeout)(implicit m: Manifest[T]): Seq[ActorRef] = {

(1 to actorCount).map {

i =>

TypedActor.get(system).getActorRefFor(TypedActor.get(system).typedActorOf(TypedProps(Reflect(system).actorClassFor(className.get)).withTimeout(timeout)))

}

}

view rawtype-actors-routing.scala hosted with โค by GitHub

The code is quite simple and allows us to use a beautiful architecture. With this, we have a system that is easily scalable and we are still using Akkaโ€™s typed actors.

Thatโ€™s it for this week. Hope you find this useful and can use it in your projects.


Edit: We just published an ebook: โ€œThe Ultimate Guide to Code Reviewโ€ based on a survey of 680+ developers. Enjoy!


About Codacy

Codacy is used by thousands of developers to analyze billions of lines of code every day!

Getting started is easy โ€“ and free! Just use yourย ย GitHub, Bitbucket or Google account toย sign up.

GET STARTED

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Subscribe to our newsletter

To be updated with all the latest news, offers and special announcements.

Recent posts

How does code quality fit into your CI/CD pipeline?

Continuous Integration and Continuous Deployment (CI/CD) are key for organizations wanting to deliver software at scale. CI/CD allows developers to automate...

How Stim uses Codacy to achieve high-quality code

We spoke with Tobias Sjรถsten, Head of Software Engineering at Stim, about how Codacy helps them guarantee code quality and standardization...

6 things developers should do to ship more secure code

Writing better, more secure source code is fundamental to prevent potential exploits and attacks that could undermine your software applications. However,...

Best practices for security code reviews

In today's interconnected world, where data breaches and cyber threats are increasingly common, one of your top priorities should be to...

April Product Update ๐Ÿš€

Hi there ๐Ÿ‘‹ It's been a whirlwind month, and we have big news to share: