File Coverage

blib/lib/Mojolicious/Plugin/Minion/Overview/Backend/mysql.pm
Criterion Covered Total %
statement 6 86 6.9
branch 0 10 0.0
condition 0 4 0.0
subroutine 2 11 18.1
pod 7 7 100.0
total 15 118 12.7


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::Minion::Overview::Backend::mysql;
2 1     1   7 use Mojo::Base 'Mojolicious::Plugin::Minion::Overview::Backend';
  1         2  
  1         6  
3              
4 1     1   590 use Mojo::JSON qw(decode_json);
  1         22989  
  1         1477  
5              
6              
7             =head2 failed_jobs
8              
9             Search failed jobs
10              
11             =cut
12              
13             sub failed_jobs {
14 0     0 1   return shift->where('state', 'failed')
15             ->jobs();
16             }
17              
18             =head2 job_runtime_metrics
19              
20             Job runtime metrics
21              
22             =cut
23              
24             sub job_runtime_metrics {
25 0     0 1   my ($self, $job) = @_;
26              
27 0           my $start = $self->start;
28              
29 0           my $sql = <
30             SELECT
31             `started` AS `x`,
32             TIME_TO_SEC(TIMEDIFF(COALESCE(`finished`, NOW()), `started`)) AS `y`,
33             `state`
34             FROM `minion_jobs`
35             WHERE
36             `task` = ?
37             AND `created` >= $start
38             ORDER BY `minion_jobs`.`created`
39             LIMIT 1000
40             SQL
41            
42 0           my $collection = $self->db->query($sql, $job)->hashes;
43              
44 0           return $collection;
45             }
46              
47             =head2 job_throughput_metrics
48              
49             Job throughput metrics
50              
51             =cut
52              
53             sub job_throughput_metrics {
54 0     0 1   my ($self, $job) = @_;
55              
56 0           my $start = $self->start;
57              
58 0           my $sql = <
59             SELECT
60             DATE_FORMAT(`started`, "%Y-%m-%d %H:00:00") AS `x`,
61             COUNT(*) AS `y`,
62             `state`
63             FROM `minion_jobs`
64             WHERE
65             `task` = ?
66             AND `created` >= $start
67             GROUP BY `x`, `state`
68             ORDER BY `x` ASC
69             LIMIT 1000
70             SQL
71            
72 0           my $collection = $self->db->query($sql, $job)->hashes;
73              
74 0           return $collection;
75             }
76              
77             =head2 jobs
78              
79             Search jobs
80              
81             =cut
82              
83             sub jobs {
84 0     0 1   my $self = shift;
85              
86 0           my @where = ('`created` >= ' . $self->start);
87 0           my @params;
88              
89             # Search by term
90 0 0         if (my $term = $self->query->{ term }) {
91 0           push(@where, 'CONCAT(`task`, CAST(`notes` AS CHAR)) LIKE ?');
92 0           push(@params, '%' . $term . '%');
93             }
94              
95             # Search where fields
96 0           for my $field (keys(%{ $self->query->{ where } })) {
  0            
97 0           push(@where, "`$field` = ?");
98 0           push(@params, $self->query->{ where }->{ $field });
99             }
100              
101             # Search tags
102 0           for my $tag (@{ $self->query->{ tags } }) {
  0            
103 0           push(@where, '(`notes` LIKE ? OR `task` = ?)');
104 0           push(@params, '%"tags":[%' . $tag . '%]%', $tag);
105             }
106              
107 0           my $where_clause = join("\n and ", @where);
108              
109 0           my $sql_count = <
110             SELECT
111             count(*) AS `total`
112             FROM `minion_jobs`
113             LEFT JOIN `minion_jobs_depends` ON `minion_jobs_depends`.`child_id` = `minion_jobs`.`id`
114             WHERE
115             $where_clause
116             SQL
117              
118 0           my $total = $self->db->query($sql_count, @params)->hash->{ total };
119              
120 0           my $sql = <
121             SELECT
122             `minion_jobs`.*,
123             `minion_jobs_depends`.`parent_id`,
124             TIME_TO_SEC(TIMEDIFF(IF(`finished` = '0000-00-00 00:00:00', NOW(), `finished`), IF(`started` = '0000-00-00 00:00:00', NOW(), `started`))) AS `runtime`
125             FROM `minion_jobs`
126             LEFT JOIN `minion_jobs_depends` ON `minion_jobs_depends`.`child_id` = `minion_jobs`.`id`
127             WHERE
128             $where_clause
129             ORDER BY `minion_jobs`.`created` DESC
130             LIMIT ?
131             OFFSET ?
132             SQL
133              
134 0           my $offset = ($self->query->{ page } - 1) * $self->query->{ limit };
135              
136 0           push(@params, $self->query->{ limit }, $offset);
137            
138 0           my $collection = $self->db->query($sql, @params)->hashes;
139 0           my $count = scalar(@$collection);
140              
141             $collection->each(sub {
142 0     0     my $object = shift;
143              
144 0 0         $object->{ tags } = eval { decode_json($object->{ notes })->{ tags } || [$object->{ task }] };
  0            
145 0           });
146              
147             my $response = {
148             results => $collection,
149             query => {
150 0           %{ $self->query },
151             total => $total,
152             prev_page => {
153             term => $self->query->{ term },
154             tags => $self->query->{ tags },
155             page => ($self->query->{ page } - 1) || 0,
156 0           %{ $self->query->{ where } }
157             },
158             next_page => {
159             term => $self->query->{ term },
160             tags => $self->query->{ tags },
161             page => $count < $self->query->{ limit } ? $self->query->{ page } : $self->query->{ page } + 1,
162 0 0 0       %{ $self->query->{ where } }
  0            
163             }
164             },
165             };
166              
167             # Clear query
168 0           $self->clear_query;
169              
170 0           return $response;
171             }
172              
173             =head2 overview
174              
175             Dashboard overview
176              
177             =cut
178              
179             sub overview {
180 0     0 1   my $self = shift;
181              
182 0           my $start = $self->start;
183              
184 0           my $sql = <
185             SELECT
186             COALESCE(SUM(IF(state = 'finished', 1, 0)), 0) AS `finished`,
187             COALESCE(SUM(IF(state = 'failed', 1, 0)), 0) AS `failed`,
188             COALESCE(SUM(IF(state = 'inactive', 1, 0)), 0) AS `inactive`
189             FROM `minion_jobs`
190             WHERE
191             `created` >= $start
192             AND `state` IN ('finished', 'failed')
193             SQL
194            
195 0           my $jobs = $self->db->query($sql)->hash;
196              
197 0           $sql = <
198             SELECT
199             COUNT(*) AS `workers`
200             FROM `minion_workers`
201             SQL
202            
203 0           my $workers = $self->db->query($sql)->hash->{ workers };
204              
205             return [
206             {
207             title => 'Finished jobs',
208             count => $jobs->{ finished },
209             },
210             {
211             title => 'Failed jobs',
212             count => $jobs->{ failed },
213             },
214             {
215             title => 'Inactive jobs',
216             count => $jobs->{ inactive },
217             },
218             {
219 0           title => 'Active workers',
220             count => $workers,
221             },
222             ];
223             }
224              
225             =head2 unique_jobs
226              
227             Search the list of unique jobs
228              
229             =cut
230              
231             sub unique_jobs {
232 0     0 1   my $self = shift;
233              
234 0           my @where = ('`created` >= ' . $self->start, "`state` IN ('finished', 'failed')");
235 0           my @params;
236              
237             # Search by term
238 0 0         if (my $term = $self->query->{ term }) {
239 0           push(@where, 'CONCAT(`task`, CAST(`notes` AS CHAR)) LIKE ?');
240 0           push(@params, '%' . $term . '%');
241             }
242              
243 0           my $where_clause = join("\n and ", @where);
244              
245 0           my $sql_count = <
246             SELECT
247             COUNT(DISTINCT(`task`)) AS `total`
248             FROM `minion_jobs`
249             WHERE
250             $where_clause
251             SQL
252              
253 0           my $total = $self->db->query($sql_count)->hash->{ total };
254              
255 0           my $sql = <
256             SELECT
257             `task`,
258             CAST(COALESCE(`finished_in` / `finished`, 0) AS DECIMAL(10,2)) AS `finished`,
259             CAST(COALESCE(`failed_in` / `failed`, 0) AS DECIMAL(10,2)) AS `failed`
260             FROM (
261             SELECT
262             `task`,
263             SUM(IF(`state` = 'finished', TIME_TO_SEC(TIMEDIFF(`finished`, `started`)), 0)) AS `finished_in`,
264             SUM(IF(`state` = 'finished', 1, 0)) AS `finished`,
265             SUM(IF(`state` = 'failed', TIME_TO_SEC(TIMEDIFF(`finished`, `started`)), 0)) AS `failed_in`,
266             SUM(IF(`state` = 'failed', 1, 0)) AS `failed`
267              
268             FROM `minion_jobs`
269             WHERE
270             $where_clause
271             GROUP BY `task`
272             LIMIT ?
273             OFFSET ?
274             ) AS `metrics`
275             ORDER BY COALESCE(`finished_in` / `finished`, 0) DESC
276             SQL
277              
278 0           my $offset = ($self->query->{ page } - 1) * $self->query->{ limit };
279            
280 0           push(@params, $self->query->{ limit }, $offset);
281            
282 0           my $collection = $self->db->query($sql, @params)->hashes;
283 0           my $count = scalar(@$collection);
284              
285             my $response = {
286             results => $collection,
287             query => {
288 0           %{ $self->query },
289             total => $total,
290              
291             prev_page => {
292             term => $self->query->{ term },
293             tags => $self->query->{ tags },
294             page => ($self->query->{ page } - 1) || 0,
295 0           %{ $self->query->{ where } }
296             },
297             next_page => {
298             term => $self->query->{ term },
299             tags => $self->query->{ tags },
300             page => $count < $self->query->{ limit } ? $self->query->{ page } : $self->query->{ page } + 1,
301 0 0 0       %{ $self->query->{ where } }
  0            
302             }
303             },
304             };
305            
306             # Clear query
307 0           $self->clear_query;
308              
309 0           return $response;
310             }
311              
312             =head2 workers
313              
314             Get workers information
315              
316             =cut
317              
318             sub workers {
319 0     0 1   my $self = shift;
320              
321 0           my $sql = <
322             SELECT *
323             FROM `minion_workers`
324             SQL
325              
326 0           my $stats_sql = <
327             SELECT
328             COUNT(*) AS `performed`,
329             COALESCE(SUM(IF(state = 'active', 1, 0)), 0) AS `active`,
330             COALESCE(SUM(IF(state = 'finished', 1, 0)), 0) AS `finished`,
331             COALESCE(SUM(IF(state = 'failed', 1, 0)), 0) AS `failed`
332             FROM `minion_jobs`
333             INNER JOIN `minion_workers` on `minion_workers`.`id` = `minion_jobs`.`worker`
334             WHERE
335             `minion_workers`.`id` = ?
336             SQL
337            
338 0           my $collection = $self->db->query($sql)->hashes;
339              
340             $collection->each(sub {
341 0     0     my $object = shift;
342              
343 0           $object->{ status } = eval { decode_json($object->{ status }) };
  0            
344 0           $object->{ jobs_stats } = $self->db->query($stats_sql, $object->{ id })->hash;
345 0           });
346              
347 0           return $collection;
348             }
349              
350             1;