How to create singleton parent actor?

Hi, I am new to Akka and developing a spring boot application integrated with Akka.

I have a root actor, which has few child actors. This root actor is the one which receives all the messages then forwards them to child actors based on the type. Now, I want to have only single instance of the root actor in the system, so specified that in the application.conf file. Also, I want to return the same ActorRef of root actor, each time actorOf() is called (since it will receive lot of messages, and I don’t want to create new instance each time , which in turn will create new child actors instances).
So, I created a wrapper over it.

RootActor :

@Component("rootActor")
@Scope("prototype")
public class RootActor extends UntypedActor{

   private static final String addOnsActorName = "addOnsActor";
   private static final String assetsActorName = "assetsActor";

   static volatile ActorRef addOnsActorRef = null;
   static volatile ActorRef assetsActorRef = null;

   @Inject
   private ActorSystem actorSystem;

   @PostConstruct
   public void init() {
      addOnsActorRef = createChild(addOnsActorName);
      assetsActorRef = createChild(assetsActorName);
   }

   public void onReceive(Object arg0) throws Exception {
      if(!(arg0 instanceof Notification)) {
        throw new InvalidMessageException("Invalid message!!");
      }

      Notification message = (Notification)arg0;
      Type type = message.getResourceType();
       if(type=="ADDONS") {
            addOnsActorRef.tell(message, self());
       }
       if(type=="ASSETS") {
            assetsActorRef.tell(message, self());
       }
   }

   public ActorRef createChild(String childName) {
      return getContext().actorOf(SpringExtProvider.get(actorSystem).props(childName).withRouter(new FromConfig()), childName);
   }
}

RootActorWrapper :

@Component
public class RootActorWrapper {

    @Inject
    ActorSystem actorSystem;

    protected ActorRef rootActor = null;

    @PostConstruct
    public void init() throws ActorException {
        try {
            rootActor = actorSystem.actorOf(SpringExtProvider.get(actorSystem)
                    .props("rootActor")
                    .withRouter(new FromConfig()),
                    "rootActor");
       } catch (Throwable e) {
            //handle error
        }
    }

    public void process(Notification notification) {
        rootActor.tell(notification, null);
    }
}

I want to know if this is alright or is there a better way to do this? Reason I want to keep root actor as singleton because it creates child actors (with 20 instances each). Hence I don’t want new instance of root actor to be created due to each actorOf() call.

So is doing this is okay? Or this is an anti-pattern?

Thanks in advance!

Hi @syadav,

from reading
https://doc.akka.io/docs/akka-modules/1.3.1/modules/spring.html as well as https://www.baeldung.com/akka-with-spring, it looks like you just have to change

@Component("rootActor")
@Scope("prototype")
public class RootActor extends UntypedActor{

to

@Component("rootActor")
@Scope("singleton")
public class RootActor extends UntypedActor{

additional, its wise to not use spring annotations (like @PostConstruct) inside your actors.

Try to use constructor injection instead of property injection. You do not need to inject an ActorSystem, as you already can access it by using context().system

Do not use static volatile in your actors class. Do not access the actors state by any other means than sending a message and receiving an answer. E.g. never do RootActor.addOnsActorRef .

For creating a child, its enough to just do a context.actorOf().
You should only need the SpringExtProvider if your child actor needs to inject dependencies managed by spring.

as to your RootActorWrapper, you should not need that if you set the scope to singleton. The extension should give you the same actorRef everytime you call something like
ActorRef actorRef = (ActorRef) context.getBean("rootActor");

Hope that helps.

Btw. your RootActor is actually a Router, as its routing messages to different other actors. You might want to rename it ;)

Actually I tried making scope singleton at first, but then service itself didn’t come up saying error in bean creation. Then changed the scope back to prototype and it worked.

About static volatile ActorRefs, I am not accessing them from outside. I need 20 instances of each child actor. Hence even these addOnsActorRef or assetsActorRef are Routers only, correct? And I don’t want to create these routers again and again.
If there is any other pattern for this kind of use-case, I am open to using that :slight_smile:

And Thanks for pointing out this :

and this :

Hmm… I’d need to know what these Actors do to decide if they are Routers or not.

Why do you think that these will be created again and again? once you create your rootActor as a singleton, the addOnsActorRef and assetsActorRef will get filled exactly once with the ActorRef to the corresponding actors… from there on, they will stay the same.

If you could describe your use-case a little more, I can try to give better advice.

Oh, I thought when we give .withRouter() , actor becomes router.

If I am not able to create a single instance of root actor, then they will be created again, each time root actor gets replaced with new instance.