|
| 1 | +use v5.36; |
1 | 2 | use Mojolicious::Lite;
|
2 | 3 | use Mojo::Pg;
|
3 | 4 | use Mojo::Promise;
|
4 | 5 |
|
5 |
| -use Cpanel::JSON::XS 'encode_json'; |
6 | 6 | use Scalar::Util 'looks_like_number';
|
7 |
| -use Data::Dumper; |
8 | 7 |
|
9 | 8 | # configuration
|
10 | 9 |
|
| 10 | +use constant MAX_DB_CONCURRENCY => 50; |
| 11 | + |
11 | 12 | {
|
12 | 13 | my $nproc = `nproc`;
|
13 | 14 | app->config(hypnotoad => {
|
14 |
| - accepts => 0, |
15 |
| - clients => int( 256 / $nproc ) + 1, |
| 15 | + accepts => 100000, |
| 16 | + clients => MAX_DB_CONCURRENCY, |
16 | 17 | graceful_timeout => 1,
|
17 | 18 | requests => 10000,
|
18 | 19 | workers => $nproc,
|
19 | 20 | backlog => 256
|
20 | 21 | });
|
21 | 22 | }
|
22 | 23 |
|
23 |
| -{ |
24 |
| - my $db_host = 'tfb-database'; |
25 |
| - helper pg => sub { state $pg = Mojo::Pg->new('postgresql://benchmarkdbuser:benchmarkdbpass@' . $db_host . '/hello_world')->max_connections(50) }; |
26 |
| -} |
27 |
| - |
28 |
| -helper render_json => sub { |
29 |
| - my $c = shift; |
30 |
| - $c->res->headers->content_type('application/json'); |
31 |
| - $c->render( data => encode_json(shift) ); |
32 |
| -}; |
33 |
| - |
34 | 24 | # Routes
|
35 | 25 |
|
36 |
| -get '/json' => sub { shift->helpers->render_json({message => 'Hello, World!'}) }; |
| 26 | +get '/json' => sub ($c) { |
| 27 | + $c->render(json => {message => 'Hello, World!'}); |
| 28 | +}; |
37 | 29 |
|
38 |
| -get '/db' => sub { shift->helpers->render_query(1, {single => 1}) }; |
| 30 | +get '/db' => sub ($c) { |
| 31 | + $c->helpers->render_query(1, {single => 1}); |
| 32 | +}; |
39 | 33 |
|
40 |
| -get '/queries' => sub { |
41 |
| - my $c = shift; |
| 34 | +get '/queries' => sub ($c) { |
42 | 35 | $c->helpers->render_query(scalar $c->param('queries'));
|
43 | 36 | };
|
44 | 37 |
|
45 |
| -get '/fortunes' => sub { |
46 |
| - my $c = shift; |
| 38 | +get '/fortunes' => sub ($c) { |
47 | 39 | $c->render_later;
|
48 |
| - my $docs = $c->helpers->pg->db->query_p('SELECT id, message FROM Fortune') |
49 |
| - ->then(sub{ |
50 |
| - my $docs = $_[0]->arrays; |
51 |
| - push @$docs, [0, 'Additional fortune added at request time.']; |
52 |
| - $c->render(fortunes => docs => $docs->sort(sub{ $a->[1] cmp $b->[1] }) ) |
53 |
| - }); |
| 40 | + |
| 41 | + $c->helpers->pg->db->query_p('SELECT id, message FROM Fortune') |
| 42 | + ->then(sub ($query) { |
| 43 | + my $docs = $query->arrays; |
| 44 | + push @$docs, [0, 'Additional fortune added at request time.']; |
| 45 | + |
| 46 | + $c->render(fortunes => docs => $docs->sort(sub { $a->[1] cmp $b->[1] })); |
| 47 | + }); |
54 | 48 | };
|
55 | 49 |
|
56 |
| -get '/updates' => sub { |
57 |
| - my $c = shift; |
| 50 | +get '/updates' => sub ($c) { |
58 | 51 | $c->helpers->render_query(scalar $c->param('queries'), {update => 1});
|
59 | 52 | };
|
60 | 53 |
|
61 | 54 | get '/plaintext' => { text => 'Hello, World!', format => 'txt' };
|
62 | 55 |
|
63 | 56 | # Additional helpers (shared code)
|
64 | 57 |
|
65 |
| -helper 'render_query' => sub { |
66 |
| - my ($self, $q, $args) = @_; |
| 58 | +helper pg => sub { |
| 59 | + state $pg = Mojo::Pg |
| 60 | + ->new('postgresql://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world') |
| 61 | + ->max_connections(MAX_DB_CONCURRENCY + 1); |
| 62 | +}; |
| 63 | + |
| 64 | +helper 'render_query' => sub ($self, $q, $args = {}) { |
67 | 65 | $self->render_later;
|
68 |
| - $args ||= {}; |
69 |
| - my $update = $args->{update}; |
70 | 66 |
|
71 | 67 | $q = 1 unless looks_like_number($q);
|
72 | 68 | $q = 1 if $q < 1;
|
73 | 69 | $q = 500 if $q > 500;
|
74 | 70 |
|
75 |
| - my $r = []; |
76 |
| - my $tx = $self->tx; |
| 71 | + Mojo::Promise->map({concurrency => MAX_DB_CONCURRENCY}, sub { |
| 72 | + my $db = $self->helpers->pg->db; |
| 73 | + my $id = 1 + int rand 10_000; |
77 | 74 |
|
| 75 | + my $query = $db->query('SELECT id, randomnumber FROM World WHERE id=?', $id); |
| 76 | + my $number = $query->array->[1]; |
78 | 77 |
|
79 |
| - my @queries; |
80 |
| - foreach (1 .. $q) { |
81 |
| - my $id = 1 + int rand 10_000; |
| 78 | + if ($args->{update}) { |
| 79 | + $number = 1 + int rand 10_000; |
| 80 | + $db->query('UPDATE World SET randomnumber=? WHERE id=?', $number, $id); |
| 81 | + } |
82 | 82 |
|
83 |
| - push @queries, $self->helpers->pg->db->query_p('SELECT id,randomnumber FROM World WHERE id=?', $id) |
84 |
| - ->then(sub{ |
85 |
| - my $randomNumber = $_[0]->array->[0]; |
86 |
| - |
87 |
| - return Mojo::Promise->new->resolve($id, $randomNumber) |
88 |
| - ->then(sub{ |
89 |
| - if($update) { |
90 |
| - $randomNumber = 1 + int rand 10_000; |
91 |
| - return Mojo::Promise->all( |
92 |
| - Mojo::Promise->new->resolve($_[0], $randomNumber), |
93 |
| - $self->helpers->pg->db->query_p('UPDATE World SET randomnumber=? WHERE id=?', $randomNumber, $id) |
94 |
| - ) |
95 |
| - ->then(sub { |
96 |
| - return $_[0]; |
97 |
| - }) |
98 |
| - } |
99 |
| - return [shift, shift]; |
100 |
| - }) |
101 |
| - }); |
102 |
| - } |
| 83 | + return Mojo::Promise->resolve([$id, $number]); |
| 84 | + }, 1 .. $q) |
| 85 | + ->then(sub (@responses) { |
| 86 | + my @results; |
103 | 87 |
|
104 |
| - Mojo::Promise->all(@queries) |
105 |
| - ->then(sub{ |
106 |
| - my @responses = @_; |
107 | 88 | foreach my $resp (@responses) {
|
108 |
| - push @$r, { id => $resp->[0][0], randomNumber => $resp->[0][1] }; |
| 89 | + push @results, { id => $resp->[0][0], randomNumber => $resp->[0][1] }; |
109 | 90 | }
|
110 |
| - $r = $r->[0] if $args->{single}; |
111 |
| - $self->helpers->render_json($r); |
112 |
| - }) |
113 | 91 |
|
| 92 | + if ($args->{single}) { |
| 93 | + $self->render(json => $results[0]); |
| 94 | + } |
| 95 | + else { |
| 96 | + $self->render(json => \@results); |
| 97 | + } |
| 98 | + }); |
114 | 99 | };
|
115 | 100 |
|
116 | 101 | app->start;
|
|
133 | 118 | </table>
|
134 | 119 | </body>
|
135 | 120 | </html>
|
| 121 | +
|
0 commit comments