Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Akka and Spring integration

Tags:

java

spring

akka

I am trying to get akka working with a spring app. It's a search app that fits the akka model perfectly. Most of the example online and on typesafe regarding this integration talk about using the akka extension to inject the spring application context. However, they all use ActorSystem.actorOf() method to create the actors which is known to be expensive operation.

ActorSystem system = ctx.getBean(ActorSystem.class);
system.actorOf(.....)

See - https://github.com/typesafehub/activator-akka-java-spring/blob/master/src/main/java/sample/Main.java

I want to use actors to process every web request that passes authentication. With the above code, I will end up creating root actor for every single request which is not ideal.

Any pointers would be really appreciated.

like image 889
Kay Avatar asked Nov 13 '14 23:11

Kay


1 Answers

The below doesn't answer the original question which is about the reducing the number of new actors that need to be created generally when a request comes into to the web app.

To do this with using an Akka router it can be as simple as the following line of code:

getContext().actorOf(SpringExtProvider.get(getContext().system()).props("AnotherActor.").withRouter(new RoundRobinPool(100)), "another");

The Akka docs provide much more detail regarding configuration though so worth taking a look http://doc.akka.io/docs/akka/snapshot/java/routing.html. It may be preferable to define their behaviour via the Akka config file rather than hard-coded into the app. You can call it like:

getContext().actorOf(SpringExtProvider.get(getContext().system()).props("AnotherActor.").withRouter(new FromConfig()), "another");

..and define the type and behviour of the router in your application.conf file.

If you've not already considered it, it's also worth checking out how to make your web rerquests asynchronous. One approach would be to use Spring's DeferredResult and pass an instance of that to your actor and set the result on completion of the search request.

--Update 20/11--

I think why the actor selection isn't working for you is because you are trying to use the bean name, not the actor name as the pacth to the actor selection. When creating the router you don't specify an actor name so it will be given a name internally by Akka, soemthing like "$a".

To illustrate, if you create your actor with:

actorSystem.actorOf(this.get(actorSystem).props(applicationContext, "bean_name"), "actorName");

Then you should be able to perform an actor selection with:

actorSystem.actorSelection("actorName");

Alternatively to create the above router actor once, and then re-use it in every request made to your Spring MVC web service, you could create it in a Spring @Configuration class and expose the ActorRef for it as a bean so you can inject into your Spring @Controller class. The following is a quick example I have created frmo memory so please make sure it is tested/compiles etc.

@Configuration
public class Config {

   @Autowired
   private ActorSystem actorSystem;

   @Bean(name = "routerActorRef")
   public ActorRef routerActorRef() { 
      getContext().actorOf(SpringExtProvider.get(actorSystem).props("AnotherActor").withRouter(new RoundRobinPool(100)), "another");
   }

}

You can then inject this into another Spring bean by writing something like:

@Autowired
@Qualifier("routerActorRef")
private ActorRef routerActorRef;

It should be noted that this is only really feasible with top-level actors, it's possible with lower level actors but will become quite tricky to manage efficiently.

-- Original answer --

The example in the Main method you link to is showing how an initial top-level actor is created that will be supervised by the system based "user" actor. It is quite a simple example that demonstrates creating a Spring managed actor named CountingActor with a Spring managed bean named CountingService injected into it.

To take this example further you could define another actor which looks similar to CountingActor e.g.

@Named("AnotherActor")
@Scope("prototype")
class AnotherActor extends UntypedActor {

  // the service that will be automatically injected
  final AnotherService anotherService;

  @Inject
  public AnotherActor(@Named("AnotherService") AnotherService anotherService) {
    this.anotherService = anotherService;
  }    

  @Override
  public void onReceive(Object message) throws Exception {
    if (message == "doSomething") {
      anotherService.doSomething();
    } else {
      unhandled(message);
    }
  }
}

I have assumed that there is another Spring service bean called AnotherService that has a method doSomething() which will be injected when the AnotherActor is created.

Then in CountingActor you can create AnotherActor like so:

@Named("CountingActor")
@Scope("prototype")
class CountingActor extends UntypedActor {

  public static class Count {}
  public static class Get {}

  // the service that will be automatically injected
  final CountingService countingService;

  @Inject
  public CountingActor(@Named("CountingService") CountingService countingService) {
    this.countingService = countingService;
  }

  private int count = 0;

  @Override
  public void onReceive(Object message) throws Exception {
    if (message instanceof Count) {
      count = countingService.increment(count);
      // Create AnotherActor here as a child of CountingActor by using the CountingActor's context
      ActorRef anotherActor = getContext().actorOf(SpringExtProvider.get(system).props("AnotherActor"), "another");
      anotherActor.tell("doSomething", getSelf());
    } else if (message instanceof Get) {
      getSender().tell(count, getSelf());
    } else {
      unhandled(message);
    }
  }
}

The key difference between the actor creation here and the one is main is the use of getContext().actorOf(...) instead of system.actorOf(...). Using getContext() causes the new actor to be created as a child of CounterActor, not the top level "user" actor.

There is a good description of this behaviour in the official Akka docs: http://doc.akka.io/docs/akka/snapshot/java/untyped-actors.html#creating-actors-with-props

like image 171
nickebbitt Avatar answered Nov 04 '22 16:11

nickebbitt