How to reject calls if custom thread-pool queue is full?

Viewed 362

Using Play Framework 2.5, how to make custom thread pool reject tasks if the pool and the queue fully busy?

Using next configuration of default and custom thread-pools.

akka {
  actor {
    default-dispatcher {
      throughput=1
      executor="thread-pool-executor"
      thread-pool-executor {
        fixed-pool-size=off
        core-pool-size=5
        max-pool-size=10
        task-queue-size=5
      }
    }
  }
}

contexts {
  custom {
    executor = "thread-pool-executor"
    throughput = 1
    thread-pool-executor {
      fixed-pool-size=10
      task-queue-size=1
    }
  }
}

And the next controller:

import akka.actor.ActorSystem;
import play.Logger;
import play.mvc.Result;
import scala.concurrent.ExecutionContextExecutor;

import javax.inject.Inject;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

import static play.mvc.Results.ok;

public class TestController {
  private final ExecutionContextExecutor executor;

  @Inject
  public TestController(ActorSystem actorSystem) {
    this.executor = actorSystem.dispatchers().lookup("contexts.custom");
  }

  public CompletionStage<Result> call() {
    return CompletableFuture.supplyAsync(this::task, executor);
  }

  private Result task() {
    Logger.info("Task started");
    sleep(5000);
    Logger.info("----- Task completed ----- ");
    return ok("ok");
  }

  private static void sleep(long millis) {
    try {
      Thread.sleep(millis);
    } catch (Exception e) {

    }
  }
}

I expect that after 10 requests, they'll start being rejected by the custom thread-pool, but instead, they are executed on the default pool.

[application-contexts.custom-14] INFO  application - Task started
[application-contexts.custom-16] INFO  application - Task started
[application-contexts.custom-15] INFO  application - Task started
[application-contexts.custom-20] INFO  application - Task started
[application-contexts.custom-19] INFO  application - Task started
[application-contexts.custom-17] INFO  application - Task started
[application-contexts.custom-21] INFO  application - Task started
[application-contexts.custom-18] INFO  application - Task started
[application-contexts.custom-22] INFO  application - Task started
[application-contexts.custom-23] INFO  application - Task started
[application-akka.actor.default-dispatcher-7] INFO  application - Task started
[application-akka.actor.default-dispatcher-10] INFO  application - Task started
[application-akka.actor.default-dispatcher-6] INFO  application - Task started
[application-akka.actor.default-dispatcher-9] INFO  application - Task started
[application-akka.actor.default-dispatcher-4] INFO  application - Task started
[application-akka.actor.default-dispatcher-12] INFO  application - Task started
[application-akka.actor.default-dispatcher-13] INFO  application - Task started
[application-akka.actor.default-dispatcher-2] INFO  application - Task started
[application-akka.actor.default-dispatcher-8] INFO  application - Task started
[application-akka.actor.default-dispatcher-5] INFO  application - Task started
[application-akka.actor.default-dispatcher-3] INFO  application - Task started
[application-akka.actor.default-dispatcher-11] INFO  application - Task started

That means that the default pool will be busy and won't process other requests unless it completes all heavy tasks. I want my custom pool to reject tasks if the pool is full and the queue full as well. Is that possible?

1 Answers

You can create your execution context programmatically with the desired logic for example with the ExecutionContext.fromExecutor(new ThreadPoolExecutor(...)). You may also implement your own akka.dispatch.ExecutorServiceConfigurator and specify its fully qualified class name in the config: docs here

my-thread-pool-dispatcher {
  # Dispatcher is the name of the event-based dispatcher
  type = Dispatcher
  # What kind of ExecutionService to use
  executor = "<Class name of the configurator>"

}
Related