Application.java 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. package controllers;
  2. import com.google.inject.name.Named;
  3. import models.Fortune;
  4. import models.World;
  5. import play.Play;
  6. import play.libs.F;
  7. import play.libs.Json;
  8. import play.mvc.Controller;
  9. import play.mvc.Result;
  10. import play.mvc.With;
  11. import scala.concurrent.ExecutionContext;
  12. import utils.Headers;
  13. import utils.Predicate;
  14. import utils.Predicated;
  15. import java.util.ArrayList;
  16. import java.util.Collections;
  17. import java.util.List;
  18. import java.util.Random;
  19. import java.util.concurrent.ThreadLocalRandom;
  20. import java.util.concurrent.ThreadPoolExecutor;
  21. import javax.inject.Inject;
  22. @With(Headers.class)
  23. public class Application extends Controller {
  24. private static final int TEST_DATABASE_ROWS = 10000;
  25. @Inject @Named("dbEc") private ExecutionContext dbEc;
  26. // If the thread-pool used by the database grows too large then our server
  27. // is probably struggling, and we should start dropping requests. Set
  28. // the max size of our queue something above the number of concurrent
  29. // connections that we need to handle.
  30. public static class IsDbAvailable implements Predicate {
  31. @Inject @Named("dbTpe") private ThreadPoolExecutor tpe;
  32. @Override
  33. public boolean condition() {
  34. return tpe.getQueue().size() <= 1024;
  35. }
  36. }
  37. @Predicated(predicate = IsDbAvailable.class, failed = SERVICE_UNAVAILABLE)
  38. public F.Promise<Result> db() {
  39. return getRandomWorlds(1).map(worlds -> ok(Json.toJson(worlds.get(0))));
  40. }
  41. @Predicated(predicate = IsDbAvailable.class, failed = SERVICE_UNAVAILABLE)
  42. public F.Promise<Result> queries(final String queryCountString) {
  43. return getRandomWorlds(queryCount(queryCountString)).map(worlds -> ok(Json.toJson(worlds)));
  44. }
  45. @Predicated(predicate = IsDbAvailable.class, failed = SERVICE_UNAVAILABLE)
  46. public F.Promise<Result> fortunes() {
  47. return F.Promise.promise(() -> {
  48. List<Fortune> fortunes = Fortune.findAll();
  49. fortunes.add(new Fortune("Additional fortune added at request time."));
  50. Collections.sort(fortunes, (f1, f2) -> f1.message.compareTo(f2.message));
  51. return ok(views.html.fortunes.render(fortunes));
  52. }, dbEc);
  53. }
  54. @Predicated(predicate = IsDbAvailable.class, failed = SERVICE_UNAVAILABLE)
  55. public F.Promise<Result> update(final String queryCountString) {
  56. return getRandomWorlds(queryCount(queryCountString)).map(worlds -> {
  57. Random random = ThreadLocalRandom.current();
  58. for (World world : worlds) {
  59. world.randomNumber = (long) (random.nextInt(10000) + 1);
  60. }
  61. List<World> updatedWorlds = World.save(worlds);
  62. return ok(Json.toJson(updatedWorlds));
  63. }, dbEc);
  64. }
  65. private int queryCount(String queryCountString) {
  66. int queryCount;
  67. try {
  68. queryCount = Integer.parseInt(queryCountString, 10);
  69. } catch (NumberFormatException e) {
  70. queryCount = 1;
  71. }
  72. if (queryCount < 1) {
  73. queryCount = 1;
  74. } else if (queryCount > 500) {
  75. queryCount = 500;
  76. }
  77. return queryCount;
  78. }
  79. private F.Promise<List<World>> getRandomWorlds(final int n) {
  80. return F.Promise.promise(() -> {
  81. Random random = ThreadLocalRandom.current();
  82. List<World> worlds = new ArrayList<>(n);
  83. for (int i = 0; i < n; ++i) {
  84. long randomId = random.nextInt(TEST_DATABASE_ROWS) + 1;
  85. World world = World.find(randomId);
  86. worlds.add(world);
  87. }
  88. return worlds;
  89. }, dbEc);
  90. }
  91. }