How to use Akka Actor System in a server plugin

We are planning to use Akka and Akka Streams in a Jira server plugin, using the latest Plugin Framework (4) and Spring Scanner (2.x) versions.

Is there a recommended way of using Scala and Akka in a server plugin?

We need to make sure the actor system is properly terminated if the add-on is disabled.

Can we rely on OSGI BundleActivator as used and mentioned in Akka OSGI? In that case the code will look like

import akka.actor.{ Props, ActorSystem }
import org.osgi.framework.BundleContext
import akka.osgi.ActorSystemActivator

object Activator extends ActorSystemActivator {

  def configure(context: BundleContext, system: ActorSystem) {
    registerService(context, system)
    val someActor = system.actorOf(Props[SomeActor], name = "someName")
    someActor ! SomeMessage
  }

}

Is there a more high-level way of achieving this without directly using BundleActivator and BundleContext? e.g. just using Spring annotations?

It was a while ago, so don’t sue me if the latest-and-greatest Spring usage pattern is different from now, but here’s how I did it:

public class DefaultActorSystemManager implements ActorSystemManager, ApplicationListener {
    ...
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ContextRefreshedEvent) {

            // shut down any actor system created by an earlier instance of the plugin
            actorSystemOption.foreach(shutdownActorSystem);

            // create a new actor system
            actorSystemOption = actorSystemFactory.create();

            // Spawn actors, which are supervised by the system guardian.
            accountantOption = actorSystemOption.map(spawnAccountant);
            notifierOption = actorSystemOption.map(spawnNotifier);
            primerOption = actorSystemOption.map(spawnPrimer);
            ...
        } else if (event instanceof ContextClosedEvent) {
            actorSystemOption.foreach(shutdownActorSystem);
            actorSystemOption = Option.none();
        }
    }

    private final Effect<ActorSystem> shutdownActorSystem = new Effect<ActorSystem>() {
        @Override
        public void apply(ActorSystem actorSystem) {
            log.info("Shutting down actor system");
            actorSystem.shutdown();
            actorSystem.awaitTermination();
        }
    };
    ...
}

Worked just fine.

1 Like

Thanks a lot David. May I ask how did you pass (inject) specific actors (Accountant, Notifier, …) as dependencies to other components?

In this case I didn’t need to pass the actor references around, but it would be easy enough to add getter methods to the ActorSystemManager interface, and inject that into other components.

1 Like