Application.java 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. package controllers;
  2. import akka.dispatch.ExecutionContexts;
  3. import akka.dispatch.Futures;
  4. import models.World;
  5. import play.Play;
  6. import play.core.NamedThreadFactory;
  7. import play.libs.Akka;
  8. import play.libs.F;
  9. import play.libs.Json;
  10. import static play.libs.Akka.future;
  11. import org.codehaus.jackson.node.ObjectNode;
  12. import org.codehaus.jackson.map.ObjectMapper;
  13. import play.mvc.Controller;
  14. import play.mvc.Result;
  15. import scala.concurrent.ExecutionContext;
  16. import utils.Predicate;
  17. import utils.Predicated;
  18. import java.util.ArrayList;
  19. import java.util.List;
  20. import java.util.Random;
  21. import java.util.concurrent.*;
  22. public class Application extends Controller {
  23. private static final int TEST_DATABASE_ROWS = 10000;
  24. //http://stackoverflow.com/questions/3907929/should-i-make-jacksons-objectmapper-as-static-final
  25. private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
  26. private static final int partitionCount = Play.application().configuration().getInt("db.default.partitionCount");
  27. private static final int maxConnections =
  28. partitionCount * Play.application().configuration().getInt("db.default.maxConnectionsPerPartition");
  29. private static final int minConnections =
  30. partitionCount * Play.application().configuration().getInt("db.default.minConnectionsPerPartition");
  31. private static final ThreadPoolExecutor tpe = new ThreadPoolExecutor(minConnections, maxConnections,
  32. 0L, TimeUnit.MILLISECONDS,
  33. new LinkedBlockingQueue<Runnable>(),
  34. new NamedThreadFactory("dbEc"));
  35. private static final ExecutionContext dbEc = ExecutionContexts.fromExecutorService(tpe);
  36. // A predicate for checking our ability to service database requests is determined by ensuring that the request
  37. // queue doesn't fill up beyond a certain threshold. For convenience we use the max number of connections
  38. // to determine this threshold. It is a rough check as we don't know how many queries we're going
  39. // to make or what other threads are running in parallel etc. Nevertheless, the check is adequate in order to
  40. // throttle the acceptance of requests to the size of the pool.
  41. public static class IsDbAvailable implements Predicate {
  42. @Override
  43. public boolean condition() {
  44. return (tpe.getQueue().size() < maxConnections);
  45. }
  46. }
  47. public static Result json() {
  48. final ObjectNode result = OBJECT_MAPPER.createObjectNode();
  49. result.put("message", "Hello World!");
  50. return ok(result);
  51. }
  52. @Predicated(predicate = IsDbAvailable.class, failed = SERVICE_UNAVAILABLE)
  53. public static Result db(final Integer queries) {
  54. return async(
  55. future(new Callable<Result>() {
  56. @Override
  57. public Result call() {
  58. final Random random = ThreadLocalRandom.current();
  59. final List<F.Promise<? extends World>> promises = new ArrayList<F.Promise<? extends World>>(queries);
  60. for (int i = 0; i < queries; ++i) {
  61. // There's no convenience method for submitting a future on an EC in Java. There is
  62. // an issue that will address this though: https://github.com/playframework/Play20/issues/972
  63. // Meanwhile we call the Akka future directly and wrap its result in a promise.
  64. final F.Promise p = Akka.asPromise(Futures.future(
  65. findWorld(Long.valueOf(random.nextInt(TEST_DATABASE_ROWS) + 1)), dbEc));
  66. promises.add(p);
  67. }
  68. final List<World> worlds = F.Promise.sequence(promises).get(5L * queries, TimeUnit.SECONDS);
  69. return ok(Json.toJson(worlds));
  70. }
  71. private Callable<World> findWorld(final Long id) {
  72. return new Callable<World>() {
  73. @Override
  74. public World call() {
  75. return World.find.byId(id);
  76. }
  77. };
  78. }
  79. })
  80. );
  81. }
  82. }