workerholic 0.0.15 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,14 +2,42 @@ var App = {
2
2
  queuedJobsCountHistory: [],
3
3
  failedJobsCountHistory: [],
4
4
  jobsCompletedHistory: [],
5
+ jobsCompletedPerSecondHistory: [],
5
6
  totalMemoryHistory: [],
7
+ maxTime: 240,
8
+ freshDataCount: function() {
9
+ return (this.maxTime / 5) + 1;
10
+ },
6
11
  tab: null,
12
+ removeStaleData: function() {
13
+ if (this.queuedJobsCountHistory.length > this.freshDataCount) {
14
+ this.queuedJobsCountHistory.pop();
15
+ this.failedJobsCountHistory.pop();
16
+ this.jobsCompletedHistory.pop();
17
+ this.totalMemoryHistory.pop();
18
+ }
19
+ },
20
+ getUrlParameter: function(param) {
21
+ var pageUrl = decodeURIComponent(window.location.search.substring(1));
22
+ var urlVariables = pageUrl.split('&')
23
+ var parameterName;
24
+
25
+ for (var i = 0; i < urlVariables.length; i++) {
26
+ parameterName = urlVariables[i].split('=');
27
+
28
+ if (parameterName[0] === param) {
29
+ return parameterName[1] === undefined ? true : parameterName[1];
30
+ }
31
+ }
32
+ },
7
33
  getOverviewData: function() {
8
34
  $.ajax({
9
35
  url: '/overview-data',
10
36
  context: this,
11
37
  success: function(data) {
12
38
  var deserializedData = JSON.parse(data);
39
+ var workersCount = deserializedData.workers_count;
40
+ var scheduledJobsCount = deserializedData.scheduled_jobs;
13
41
 
14
42
  var completedJobs = deserializedData.completed_jobs.reduce(function(sum, subArray) {
15
43
  return sum + subArray[1];
@@ -25,29 +53,34 @@ var App = {
25
53
  return sum + queue[1];
26
54
  }, 0);
27
55
 
28
- // var totalMemory = deserializedData.memory_usage ...
56
+ var memoryUsage = deserializedData.memory_usage;
57
+ var totalMemoryUsage = 0;
58
+
59
+ for (id in memoryUsage) {
60
+ totalMemoryUsage = totalMemoryUsage + parseInt(memoryUsage[id]);
61
+ if ($('#process_' + id).length === 1) {
62
+ $('#process_' + id).text(parseInt(memoryUsage[id]) / 1000 + ' MB');
63
+ } else {
64
+ $('.nested').last().after("<tr class='nested'><td>" + id + "</td><td id='process_" + id + "''>" + memoryUsage[id] + "</td></tr>")
65
+ }
66
+ }
29
67
 
30
68
  this.queuedJobsCountHistory.unshift(queuedJobsCount);
31
69
  this.failedJobsCountHistory.unshift(failedJobsCount);
32
70
  this.jobsCompletedHistory.unshift(completedJobs);
33
- // totalMemoryHistory.unshift(totalMemory); Waiting for data
34
-
35
- if (this.queuedJobsCountHistory.length > 13) {
36
- this.queuedJobsCountHistory.pop();
37
- this.failedJobsCountHistory.pop();
38
- this.jobsCompletedHistory.pop();
39
- this.totalMemoryHistory.pop();
40
- }
71
+ this.totalMemoryHistory.unshift(totalMemoryUsage / 1000);
72
+ this.jobsCompletedPerSecondHistory.unshift((this.jobsCompletedHistory[0] - this.jobsCompletedHistory[1]) / 5 || 0);
41
73
 
74
+ this.removeStaleData();
42
75
  this.drawChart();
43
76
 
44
- var workersCount = deserializedData.workers_count;
45
-
46
77
  $('.completed_jobs').text(completedJobs);
47
78
  $('.failed_jobs').text(failedJobsCount);
48
79
  $('.queue_count').text(queuedJobs.length);
49
80
  $('.queued_jobs_count').text(queuedJobsCount);
81
+ $('.scheduled_jobs').text(scheduledJobsCount);
50
82
  $('.workers_count').text(workersCount);
83
+ $('.memory_usage').text(totalMemoryUsage / 1000 + ' MB');
51
84
  }
52
85
  });
53
86
  },
@@ -94,6 +127,33 @@ var App = {
94
127
  }
95
128
  })
96
129
  },
130
+ getHistoryData: function() {
131
+ var className = $('#class_selector select').find(':selected').val();
132
+ var days = this.getUrlParameter('days') || 7;
133
+
134
+ $('#button_' + days).addClass('is-dark');
135
+
136
+ $('#class_selector').on('change', function(e) {
137
+ location = window.location.origin + window.location.pathname + '?days=' + days + '&class=' + e.target.value;
138
+ });
139
+
140
+ $('#day_tabs a').on('click', function(e) {
141
+ e.preventDefault();
142
+ location = window.location.origin + window.location.pathname + '?days=' + $(e.target).attr('data-day') + '&class=' + className;
143
+ });
144
+
145
+ $.ajax({
146
+ url: '/historic-data',
147
+ data: {
148
+ days: days,
149
+ className: className,
150
+ },
151
+ dataType: 'json',
152
+ success: function(data) {
153
+ this.drawHistoryChart(days, className, data['completed_jobs'], data['failed_jobs']);
154
+ }.bind(this)
155
+ })
156
+ },
97
157
  drawChart: function() {
98
158
  var processedJobsChart = new CanvasJS.Chart('jobs_processed_container', {
99
159
  title: {
@@ -107,7 +167,7 @@ var App = {
107
167
  tickColor: 'silver',
108
168
  animationEnabled: true,
109
169
  title: 'Time ago (s)',
110
- maximum: 60
170
+ maximum: this.maxTime
111
171
  },
112
172
  toolTip: {
113
173
  shared: true
@@ -124,22 +184,8 @@ var App = {
124
184
  name: "Jobs completed",
125
185
  color: "blue",
126
186
  markerType: 'circle',
127
- lineThickness: 2,
128
- dataPoints: [
129
- { x: '0', y: (this.jobsCompletedHistory[0] - this.jobsCompletedHistory[1]) / 5 || 0 },
130
- { x: '5', y: (this.jobsCompletedHistory[1] - this.jobsCompletedHistory[2]) / 5 || 0 },
131
- { x: '10', y: (this.jobsCompletedHistory[2] - this.jobsCompletedHistory[3]) / 5 || 0 },
132
- { x: '15', y: (this.jobsCompletedHistory[3] - this.jobsCompletedHistory[4]) / 5 || 0 },
133
- { x: '20', y: (this.jobsCompletedHistory[4] - this.jobsCompletedHistory[5]) / 5 || 0 },
134
- { x: '25', y: (this.jobsCompletedHistory[5] - this.jobsCompletedHistory[6]) / 5 || 0 },
135
- { x: '30', y: (this.jobsCompletedHistory[6] - this.jobsCompletedHistory[7]) / 5 || 0 },
136
- { x: '35', y: (this.jobsCompletedHistory[7] - this.jobsCompletedHistory[8]) / 5 || 0 },
137
- { x: '40', y: (this.jobsCompletedHistory[8] - this.jobsCompletedHistory[9]) / 5 || 0 },
138
- { x: '45', y: (this.jobsCompletedHistory[9] - this.jobsCompletedHistory[10]) / 5 || 0 },
139
- { x: '50', y: (this.jobsCompletedHistory[10] - this.jobsCompletedHistory[11]) / 5 || 0 },
140
- { x: '55', y: (this.jobsCompletedHistory[11] - this.jobsCompletedHistory[12]) / 5 || 0 },
141
- { x: '60', y: (this.jobsCompletedHistory[12] - this.jobsCompletedHistory[13]) / 5 || 0 },
142
- ]
187
+ lineThickness: 6,
188
+ dataPoints: this.setDataPoints(this.jobsCompletedPerSecondHistory, this.freshDataCount()),
143
189
  }]
144
190
  });
145
191
 
@@ -156,7 +202,7 @@ var App = {
156
202
  animationEnabled: true,
157
203
  title: 'Time ago (s)',
158
204
  // minimum: 0,
159
- maximum: 60
205
+ maximum: this.maxTime,
160
206
  },
161
207
  toolTip: {
162
208
  shared: true
@@ -170,11 +216,11 @@ var App = {
170
216
  data: [{
171
217
  type: "line",
172
218
  showInLegend: true,
173
- lineThickness: 2,
219
+ lineThickness: 6,
174
220
  name: "Queued Jobs",
175
221
  markerType: "circle",
176
222
  color: "#F08080",
177
- dataPoints: this.setDataPoints(this.queuedJobsCountHistory),
223
+ dataPoints: this.setDataPoints(this.queuedJobsCountHistory, this.freshDataCount()),
178
224
  }],
179
225
  });
180
226
 
@@ -191,7 +237,7 @@ var App = {
191
237
  animationEnabled: true,
192
238
  title: 'Time ago (s)',
193
239
  // minimum: 0,
194
- maximum: 60
240
+ maximum: this.maxTime,
195
241
  },
196
242
  toolTip: {
197
243
  shared: true
@@ -208,8 +254,8 @@ var App = {
208
254
  name: "Failed Jobs",
209
255
  color: "#20B2AA",
210
256
  markerType: 'circle',
211
- lineThickness: 2,
212
- dataPoints: this.setDataPoints(this.failedJobsCountHistory),
257
+ lineThickness: 6,
258
+ dataPoints: this.setDataPoints(this.failedJobsCountHistory, this.freshDataCount()),
213
259
  },
214
260
  ]
215
261
  });
@@ -227,7 +273,7 @@ var App = {
227
273
  animationEnabled: true,
228
274
  title: 'Time ago (s)',
229
275
  // minimum: 0,
230
- maximum: 60
276
+ maximum: this.maxTime
231
277
  },
232
278
  toolTip: {
233
279
  shared: true
@@ -244,8 +290,8 @@ var App = {
244
290
  name: "Memory usage",
245
291
  color: "#20B2AA",
246
292
  markerType: 'circle',
247
- lineThickness: 2,
248
- dataPoints: this.setDataPoints(this.totalMemoryHistory),
293
+ lineThickness: 6,
294
+ dataPoints: this.setDataPoints(this.totalMemoryHistory, this.freshDataCount()),
249
295
  }],
250
296
  });
251
297
 
@@ -254,27 +300,110 @@ var App = {
254
300
  processedJobsChart.render();
255
301
  totalMemoryChart.render();
256
302
  },
257
- setDataPoints: function(array) {
258
- data = [
259
- { x: '0', y: array[0] },
260
- { x: '5', y: array[1] },
261
- { x: '10', y: array[2] },
262
- { x: '15', y: array[3] },
263
- { x: '20', y: array[4] },
264
- { x: '25', y: array[5] },
265
- { x: '30', y: array[6] },
266
- { x: '35', y: array[7] },
267
- { x: '40', y: array[8] },
268
- { x: '45', y: array[9] },
269
- { x: '50', y: array[10] },
270
- { x: '55', y: array[11] },
271
- { x: '60', y: array[12] },
272
- ];
303
+ drawHistoryChart: function(days, className, completed_jobs, failed_jobs) {
304
+ var completedHistoryChart = new CanvasJS.Chart('history_container_completed', {
305
+ title: {
306
+ text: 'Completed History for ' + days + ' days',
307
+ fontFamily: 'Arial',
308
+ fontSize: 24,
309
+ },
310
+ axisX: {
311
+ // reversed: true,
312
+ gridColor: 'Silver',
313
+ tickColor: 'silver',
314
+ animationEnabled: true,
315
+ title: 'Date',
316
+ minimum: parseInt((completed_jobs['date_ranges'][days]) * 1000),
317
+ },
318
+ toolTip: {
319
+ shared: true
320
+ },
321
+ theme: "theme2",
322
+ axisY: {
323
+ gridColor: "Silver",
324
+ tickColor: "silver",
325
+ title: 'Jobs'
326
+ },
327
+ data: [{
328
+ type: "line",
329
+ showInLegend: true,
330
+ name: "Completed Job for " + className,
331
+ color: "#20B2AA",
332
+ markerType: 'circle',
333
+ lineThickness: 2,
334
+ xValueType: 'dateTime',
335
+ dataPoints: this.setHistoryDataPoints(completed_jobs),
336
+ }],
337
+ });
338
+
339
+ var failedHistoryChart = new CanvasJS.Chart('history_container_failed', {
340
+ title: {
341
+ text: 'Failed History for ' + days + ' days',
342
+ fontFamily: 'Arial',
343
+ fontSize: 24,
344
+ },
345
+ axisX: {
346
+ gridColor: 'Silver',
347
+ tickColor: 'silver',
348
+ animationEnabled: true,
349
+ title: 'Date',
350
+ minimum: parseInt((completed_jobs['date_ranges'][days]) * 1000),
351
+ },
352
+ toolTip: {
353
+ shared: true
354
+ },
355
+ theme: "theme2",
356
+ axisY: {
357
+ gridColor: "Silver",
358
+ tickColor: "silver",
359
+ title: 'Jobs'
360
+ },
361
+ data: [{
362
+ type: "line",
363
+ showInLegend: true,
364
+ name: "Failed Jobs for " + className,
365
+ color: "#20B2AA",
366
+ markerType: 'circle',
367
+ lineThickness: 2,
368
+ xValueType: 'dateTime',
369
+ dataPoints: this.setHistoryDataPoints(failed_jobs),
370
+ }],
371
+ });
372
+
373
+ completedHistoryChart.render();
374
+ failedHistoryChart.render();
375
+ },
376
+ setHistoryDataPoints: function(jobs) {
377
+ data = []
378
+
379
+ for (var i = 0; i <= jobs['date_ranges'].length; i++) {
380
+ var point = { x: this.getLocalDate(parseInt(jobs['date_ranges'][i])).getTime(), y: jobs['job_counts'][i]};
381
+
382
+ data.push(point);
383
+ }
384
+
385
+ return data;
386
+ },
387
+ setDataPoints: function(array, count) {
388
+ var data = [];
389
+
390
+ for (var i = 0; i <= count; i++) {
391
+ var point = { x: (i * 5).toString(), y: array[i] };
392
+ data.push(point);
393
+ }
273
394
 
274
395
  return data;
275
396
  },
397
+ getLocalDate: function(seconds) {
398
+ var date = new Date(seconds * 1000);
399
+ var day = date.getUTCDate();
400
+ var month = date.getUTCMonth();
401
+ var year = date.getUTCFullYear();
402
+
403
+ return new Date(year, month, day);
404
+ },
276
405
  setActiveTab: function() {
277
- this.tab = $(location).attr('href').split('/').pop();
406
+ this.tab = $(location).attr('href').match(/(?:(?!\?).)*/)[0].split('/').pop();
278
407
  var $active = $('a[href=' + this.tab + ']');
279
408
 
280
409
  $active.css('background', '#a2a2a2');
@@ -300,10 +429,15 @@ var App = {
300
429
  this.getDetailData();
301
430
  }.bind(this), 5000);
302
431
  }
432
+
433
+ if (tab === 'history') {
434
+ this.getHistoryData();
435
+ }
303
436
  },
304
437
  bindEvents: function() {
305
438
  $('#memory_usage').on('click', function(e) {
306
439
  $('.nested th').toggle();
440
+ $('.nested td').toggle();
307
441
  });
308
442
  },
309
443
  init: function() {
@@ -64,10 +64,16 @@ nav a:hover {
64
64
  }
65
65
 
66
66
  .chart {
67
+ height: 300px;
68
+ width: 100%;
67
69
  margin-top: 50px;
68
70
  }
69
71
 
70
- .nested th {
72
+ .nested th, .nested td {
71
73
  display: none;
72
74
  padding-left: 50px
73
75
  }
76
+
77
+ #day_tabs {
78
+ margin-top: 50px;
79
+ }
@@ -0,0 +1,22 @@
1
+ <div id="day_tabs">
2
+ <a class='button' id="button_7" data-day="7" href='/history?days=7'>7 Days</a>
3
+ <a class='button' id="button_30" data-day="30" href='/history?days=30'>30 Days</a>
4
+ <a class='button' id="button_180" data-day="180" href='/history?days=180'>180 Days</a>
5
+ <a class='button' id="button_365" data-day="365" href='/history?days=365'>365 Days</a>
6
+ </div>
7
+
8
+ <div class="select" id="class_selector">
9
+ <select>
10
+ <option disabled>Select a class</option>
11
+ <option value='completed'>Completed</option>
12
+ <% @classes.each do |class_name| %>
13
+ <option value="<%= class_name %>" <%= 'selected' if class_name == @class %>><%= class_name %></option>
14
+ <% end %>
15
+ </select>
16
+ </div>
17
+
18
+ <div id="history_container_completed" class="chart">
19
+ </div>
20
+
21
+ <div id="history_container_failed" class="chart">
22
+ </div>
data/web/views/layout.erb CHANGED
@@ -19,8 +19,8 @@
19
19
  <li class='column'><a href='overview'>Overview</a></li>
20
20
  <li class='column'><a href='details'>Job Details</a></li>
21
21
  <li class='column'><a href='queues'>Queues</a></li>
22
- <!-- <li class='column'><a href='workers'>Workers</a></li>
23
- <li class='column'><a href='failed'>Failed</a></li>
22
+ <li class='column'><a href='history'>History</a></li>
23
+ <!-- <li class='column'><a href='failed'>Failed</a></li>
24
24
  <li class='column'><a href='scheduled'>Scheduled</a></li> -->
25
25
  </ul>
26
26
  </nav>
@@ -1,10 +1,3 @@
1
- <!-- <div id="statistics">
2
- <h2>Your current jobs overview</h2>
3
- <p id="completed">Finished Jobs: 0</p>
4
- <p>Jobs in queue: 100,000,000</p>
5
- <p id="failed">Jobs failed: 10,000,000</p>
6
- </div> -->
7
-
8
1
  <table class='table is-striped'>
9
2
  <thead>
10
3
  <tr>
@@ -21,6 +14,10 @@
21
14
  <td>Queued Jobs</td>
22
15
  <td class='queued_jobs_count count'></td>
23
16
  </tr>
17
+ <tr>
18
+ <td>Scheduled Jobs</td>
19
+ <td class='scheduled_jobs count'></td>
20
+ </tr>
24
21
  <tr>
25
22
  <td>Failed Jobs</td>
26
23
  <td class='failed_jobs count'></td>
@@ -35,23 +32,29 @@
35
32
  </tr>
36
33
  <tr id='memory_usage'>
37
34
  <td>Total Memory Usage</td>
38
- <td class='memory_usage count'>0</td>
35
+ <td class='memory_usage count'></td>
39
36
  </tr>
40
37
  <tr class='nested'>
41
38
  <th>Process Id</th>
42
39
  <th>Memory Usage</th>
43
40
  </tr>
41
+ <% @processes.each do |id, memory| %>
42
+ <tr class='nested'>
43
+ <td><%= id %></td>
44
+ <td id='process_<%= id %>'></td>
45
+ </tr>
46
+ <% end %>
44
47
  </tbody>
45
48
  </table>
46
49
 
47
- <div id="queued_jobs_container" class="chart" style="height: 300px; width: 100%">
50
+ <div id="queued_jobs_container" class="chart">
48
51
  </div>
49
52
 
50
- <div id="failed_jobs_container" class="chart" style="height: 300px; width: 100%">
53
+ <div id="failed_jobs_container" class="chart">
51
54
  </div>
52
55
 
53
- <div id="jobs_processed_container" class="chart" style="height: 300px; width: 100%">
56
+ <div id="jobs_processed_container" class="chart">
54
57
  </div>
55
58
 
56
- <div id="total_memory_container" class="chart" style="height: 300px; width: 100%">
59
+ <div id="total_memory_container" class="chart">
57
60
  </div>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: workerholic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.15
4
+ version: 0.0.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Antoine Leclercq
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2017-08-02 00:00:00.000000000 Z
13
+ date: 2017-08-04 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: redis
@@ -117,6 +117,7 @@ files:
117
117
  - LICENSE
118
118
  - README.md
119
119
  - Rakefile
120
+ - app_test/bm.rb
120
121
  - app_test/job_test.rb
121
122
  - app_test/run.rb
122
123
  - bin/workerholic
@@ -157,6 +158,8 @@ files:
157
158
  - spec/queue_spec.rb
158
159
  - spec/sorted_set_spec.rb
159
160
  - spec/spec_helper.rb
161
+ - spec/statistics_api_spec.rb
162
+ - spec/statistics_storage_spec.rb
160
163
  - spec/storage_spec.rb
161
164
  - spec/worker_balancer_spec.rb
162
165
  - spec/worker_spec.rb
@@ -166,6 +169,7 @@ files:
166
169
  - web/public/stylesheets/whitespace-reset.css
167
170
  - web/views/details.erb
168
171
  - web/views/failed.erb
172
+ - web/views/history.erb
169
173
  - web/views/layout.erb
170
174
  - web/views/overview.erb
171
175
  - web/views/queues.erb
@@ -211,6 +215,8 @@ test_files:
211
215
  - spec/queue_spec.rb
212
216
  - spec/sorted_set_spec.rb
213
217
  - spec/spec_helper.rb
218
+ - spec/statistics_api_spec.rb
219
+ - spec/statistics_storage_spec.rb
214
220
  - spec/storage_spec.rb
215
221
  - spec/worker_balancer_spec.rb
216
222
  - spec/worker_spec.rb