app.pl 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. use v5.36;
  2. use Mojolicious::Lite;
  3. use Mojo::Pg;
  4. use Mojo::Promise;
  5. use Scalar::Util 'looks_like_number';
  6. # configuration
  7. use constant MAX_DB_CONCURRENCY => 50;
  8. {
  9. my $nproc = `nproc`;
  10. app->config(hypnotoad => {
  11. accepts => 100000,
  12. clients => MAX_DB_CONCURRENCY,
  13. graceful_timeout => 1,
  14. requests => 10000,
  15. workers => $nproc,
  16. backlog => 256
  17. });
  18. }
  19. # Routes
  20. get '/json' => sub ($c) {
  21. $c->render(json => {message => 'Hello, World!'});
  22. };
  23. get '/db' => sub ($c) {
  24. $c->helpers->render_query(1, {single => 1});
  25. };
  26. get '/queries' => sub ($c) {
  27. $c->helpers->render_query(scalar $c->param('queries'));
  28. };
  29. get '/fortunes' => sub ($c) {
  30. $c->render_later;
  31. $c->helpers->pg->db->query_p('SELECT id, message FROM Fortune')
  32. ->then(sub ($query) {
  33. my $docs = $query->arrays;
  34. push @$docs, [0, 'Additional fortune added at request time.'];
  35. $c->render(fortunes => docs => $docs->sort(sub { $a->[1] cmp $b->[1] }));
  36. });
  37. };
  38. get '/updates' => sub ($c) {
  39. $c->helpers->render_query(scalar $c->param('queries'), {update => 1});
  40. };
  41. get '/plaintext' => { text => 'Hello, World!', format => 'txt' };
  42. # Additional helpers (shared code)
  43. helper pg => sub {
  44. state $pg = Mojo::Pg
  45. ->new('postgresql://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world')
  46. ->max_connections(MAX_DB_CONCURRENCY + 1);
  47. };
  48. helper 'render_query' => sub ($self, $q, $args = {}) {
  49. $self->render_later;
  50. $q = 1 unless looks_like_number($q);
  51. $q = 1 if $q < 1;
  52. $q = 500 if $q > 500;
  53. Mojo::Promise->map({concurrency => MAX_DB_CONCURRENCY}, sub {
  54. my $db = $self->helpers->pg->db;
  55. my $id = 1 + int rand 10_000;
  56. my $query = $db->query('SELECT id, randomnumber FROM World WHERE id=?', $id);
  57. my $number = $query->array->[1];
  58. if ($args->{update}) {
  59. $number = 1 + int rand 10_000;
  60. $db->query('UPDATE World SET randomnumber=? WHERE id=?', $number, $id);
  61. }
  62. return Mojo::Promise->resolve([$id, $number]);
  63. }, 1 .. $q)
  64. ->then(sub (@responses) {
  65. my @results;
  66. foreach my $resp (@responses) {
  67. push @results, { id => $resp->[0][0], randomNumber => $resp->[0][1] };
  68. }
  69. if ($args->{single}) {
  70. $self->render(json => $results[0]);
  71. }
  72. else {
  73. $self->render(json => \@results);
  74. }
  75. });
  76. };
  77. app->start;
  78. __DATA__
  79. @@ fortunes.html.ep
  80. <!DOCTYPE html>
  81. <html>
  82. <head><title>Fortunes</title></head>
  83. <body>
  84. <table>
  85. <tr><th>id</th><th>message</th></tr>
  86. % foreach my $doc (@$docs) {
  87. <tr>
  88. <td><%= $doc->[0] %></td>
  89. <td><%= $doc->[1] %></td>
  90. </tr>
  91. % }
  92. </table>
  93. </body>
  94. </html>