The official documentation offers the following solutions:
- Make a blocking call inside the actor (or a set of participants controlled by the router [Java, Scala]) to configure a thread pool that is designed for this purpose or large enough.
- Make a blocking call in the future, providing an upper bound on the number of such calls at any given time (sending an unlimited number of tasks of this kind will exhaust the limitations of your memory or thread).
- Make a blocking call in the future by providing the thread pool with an upper limit on the number of threads suitable for the equipment on which the application is running.
- Allocate a single thread to control the set of blocking resources (for example, an NIO selector that controls several channels) and send events as they appear as actor messages.
The use of futures refers to the officially proposed approaches, but with extreme caution.
Consider the first approach, since IMO is more consistent.
First of all, remove all blocking I / O operations to new members that perform only one blocking I / O operation. Suppose for brevity there is only one such operation:
public class MyBlockingIOActor extends UntypedActor { public void onReceive(Object msg) { // do blocking IO call here and send the result back to sender } }
Add a dispatcher configuration that takes care of blocking participants, an actor system configuration file (usually application.conf ):
#Configuring a dispatcher with fixed thread pool size, eg for actors that perform blocking IO blocking-io-dispatcher { type = Dispatcher executor = "thread-pool-executor" thread-pool-executor { fixed-pool-size = 32 } throughput = 1 }
Please make sure that you use the configuration file when creating the actors system (especially if you decide to use a non-standard file name for the configuration):
ActorSystem actorSystem = ActorSystem.create("my-actor-system", ConfigFactory.load("application.conf"));
After that, you want to assign an actor who performs an I / O lock for the dedicated dispatcher. You can do this in the configuration as described here or when creating the actor:
ActorRef blockingActor = context().actorOf(Props.create(MyBlockingIOActor.class).withDispatcher("blocking-io-dispatcher"));
To increase throughput, consider blocking actor blocking in the pool:
SupervisorStrategy strategy = new OneForOneStrategy( 5, Duration.create(1, TimeUnit.MINUTES), Collections.singletonList(Exception.class) ); ActorRef blockingActor = context().actorOf(new SmallestMailboxPool(5).withSupervisorStrategy(strategy).props(Props.create(MyBlockingIOActor.class).withDispatcher("blocking-io-dispatcher")));
You can verify that the actor is using the correct dispatcher as follows:
public class MyBlockingIOActor extends UntypedActor { public void preStart() { LOGGER.debug("using dispatcher: {}", ((Dispatcher)context().dispatcher()).id()); } }