workerholic 0.0.8 → 0.0.9

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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/app_test/job_test.rb +1 -6
  4. data/app_test/run.rb +47 -39
  5. data/lib/workerholic/adapters/active_job_adapter.rb +8 -6
  6. data/lib/workerholic/cli.rb +11 -4
  7. data/lib/workerholic/job.rb +3 -2
  8. data/lib/workerholic/job_processor.rb +17 -6
  9. data/lib/workerholic/job_retry.rb +5 -2
  10. data/lib/workerholic/job_scheduler.rb +5 -2
  11. data/lib/workerholic/job_serializer.rb +8 -0
  12. data/lib/workerholic/job_statistics.rb +38 -0
  13. data/lib/workerholic/job_wrapper.rb +14 -5
  14. data/lib/workerholic/manager.rb +5 -0
  15. data/lib/workerholic/statistics_api.rb +77 -0
  16. data/lib/workerholic/statistics_storage.rb +19 -0
  17. data/lib/workerholic/storage.rb +25 -0
  18. data/lib/workerholic/version.rb +1 -1
  19. data/lib/workerholic/worker.rb +3 -0
  20. data/lib/workerholic/worker_balancer.rb +0 -1
  21. data/lib/workerholic.rb +7 -1
  22. data/pkg/workerholic-0.0.8.gem +0 -0
  23. data/spec/integration/enqueuing_jobs_spec.rb +5 -3
  24. data/spec/job_processor_spec.rb +7 -7
  25. data/spec/{statistics_spec.rb → job_statistics.rb} +10 -5
  26. data/spec/job_wrapper_spec.rb +7 -4
  27. data/spec/worker_spec.rb +2 -2
  28. data/web/application.rb +13 -6
  29. data/web/public/javascripts/application.js +109 -0
  30. data/web/public/stylesheets/application.css +30 -14
  31. data/web/views/details.erb +48 -31
  32. data/web/views/failed.erb +27 -0
  33. data/web/views/index.erb +38 -33
  34. data/web/views/layout.erb +36 -0
  35. data/web/views/queues.erb +31 -0
  36. data/web/views/scheduled.erb +27 -0
  37. data/web/views/workers.erb +41 -41
  38. metadata +13 -5
  39. data/lib/workerholic/statistics.rb +0 -21
@@ -11,7 +11,7 @@ end
11
11
 
12
12
  describe Workerholic::JobProcessor do
13
13
  it 'processes a simple job' do
14
- job = Workerholic::JobWrapper.new(class: SimpleJobTest, arguments: ['test job'])
14
+ job = Workerholic::JobWrapper.new(klass: SimpleJobTest, arguments: ['test job'])
15
15
  serialized_job = Workerholic::JobSerializer.serialize(job)
16
16
 
17
17
  job_processor = Workerholic::JobProcessor.new(serialized_job)
@@ -22,9 +22,9 @@ describe Workerholic::JobProcessor do
22
22
 
23
23
  it 'processes a complex job' do
24
24
  serialized_job = Workerholic::JobSerializer.serialize({
25
- class: ComplexJobTest,
25
+ klass: ComplexJobTest,
26
26
  arguments: ['test job', { a: 1, b: 2 }, [1, 2, 3]],
27
- statistics: Workerholic::Statistics.new.to_hash
27
+ statistics: Workerholic::JobStatistics.new.to_hash
28
28
  })
29
29
 
30
30
  job_processor = Workerholic::JobProcessor.new(serialized_job)
@@ -35,9 +35,9 @@ describe Workerholic::JobProcessor do
35
35
 
36
36
  it 'does not raise an error when processing a job with error' do
37
37
  serialized_job = Workerholic::JobSerializer.serialize({
38
- class: SimpleJobTestWithError,
38
+ klass: SimpleJobTestWithError,
39
39
  arguments: [],
40
- statistics: Workerholic::Statistics.new.to_hash
40
+ statistics: Workerholic::JobStatistics.new.to_hash
41
41
  })
42
42
 
43
43
  job_processor = Workerholic::JobProcessor.new(serialized_job)
@@ -47,9 +47,9 @@ describe Workerholic::JobProcessor do
47
47
 
48
48
  it 'retries job when job processing fails' do
49
49
  job = {
50
- class: SimpleJobTestWithError,
50
+ klass: SimpleJobTestWithError,
51
51
  arguments: [],
52
- statistics: Workerholic::Statistics.new.to_hash
52
+ statistics: Workerholic::JobStatistics.new.to_hash
53
53
  }
54
54
  serialized_job = Workerholic::JobSerializer.serialize(job)
55
55
 
@@ -1,8 +1,9 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Workerholic::Statistics do
4
- it 'initializes attributes with without an argument' do
5
- statistics = Workerholic::Statistics.new
3
+ describe Workerholic::JobStatistics do
4
+ it 'initializes attributes if no argument supplied' do
5
+ statistics = Workerholic::JobStatistics.new
6
+ expect(statistics.failed_on).to be_nil
6
7
  expect(statistics.enqueued_at).to be_nil
7
8
  expect(statistics.errors).to eq([])
8
9
  expect(statistics.started_at).to be_nil
@@ -13,13 +14,17 @@ describe Workerholic::Statistics do
13
14
  enqueuing_time = Time.now.to_f - 86400
14
15
  started_at_time = Time.now.to_f
15
16
  completed_at_time = Time.now.to_f + 86400
17
+ elapsed_time = '%.10f' % (completed_at_time - started_at_time)
18
+
16
19
  options = {
17
20
  enqueued_at: enqueuing_time,
18
21
  errors: ['Your job is bad and you should feel bad'],
19
22
  started_at: started_at_time,
20
- completed_at: completed_at_time
23
+ completed_at: completed_at_time,
24
+ elapsed_time: elapsed_time,
25
+ failed_on: nil
21
26
  }
22
27
 
23
- expect(Workerholic::Statistics.new(options).to_hash).to eq(options)
28
+ expect(Workerholic::JobStatistics.new(options).to_hash).to eq(options)
24
29
  end
25
30
  end
@@ -2,10 +2,11 @@ require_relative 'spec_helper'
2
2
 
3
3
  describe Workerholic::JobWrapper do
4
4
  it 'returns a hash with job meta info and job stats info' do
5
- job = Workerholic::JobWrapper.new(class: SimpleJobTest, arguments: ['test job'])
5
+ job = Workerholic::JobWrapper.new(klass: SimpleJobTest, arguments: ['test job'])
6
6
 
7
7
  expected_result = {
8
- class: SimpleJobTest,
8
+ klass: SimpleJobTest,
9
+ wrapper: nil,
9
10
  arguments: ['test job'],
10
11
  retry_count: 0,
11
12
  execute_at: nil,
@@ -13,14 +14,16 @@ describe Workerholic::JobWrapper do
13
14
  enqueued_at: nil,
14
15
  errors: [],
15
16
  started_at: nil,
16
- completed_at: nil
17
+ completed_at: nil,
18
+ failed_on: nil,
19
+ elapsed_time: nil
17
20
  }
18
21
  }
19
22
  expect(job.to_hash).to eq(expected_result)
20
23
  end
21
24
 
22
25
  it 'performs the job' do
23
- job = Workerholic::JobWrapper.new(class: SimpleJobTest, arguments: ['test job'])
26
+ job = Workerholic::JobWrapper.new(klass: SimpleJobTest, arguments: ['test job'])
24
27
 
25
28
  expect(job.perform).to eq('test job')
26
29
  end
data/spec/worker_spec.rb CHANGED
@@ -20,9 +20,9 @@ describe Workerholic::Worker do
20
20
  let(:redis) { Redis.new }
21
21
  let(:job) do
22
22
  {
23
- class: WorkerJobTest,
23
+ klass: WorkerJobTest,
24
24
  arguments: [],
25
- statistics: Workerholic::Statistics.new.to_hash
25
+ statistics: Workerholic::JobStatistics.new.to_hash
26
26
  }
27
27
  end
28
28
 
data/web/application.rb CHANGED
@@ -1,7 +1,12 @@
1
+ require 'redis'
1
2
  require 'sinatra'
2
3
  require 'sinatra/reloader'
3
4
 
4
5
  get '/' do
6
+ redirect '/overview'
7
+ end
8
+
9
+ get '/overview' do
5
10
  erb :index
6
11
  end
7
12
 
@@ -10,21 +15,23 @@ get '/details' do
10
15
  end
11
16
 
12
17
  get '/queues' do
13
- #placeholder
14
- erb :index
18
+ erb :queues
15
19
  end
16
20
 
17
21
  get '/workers' do
18
- #placeholder
19
22
  erb :workers
20
23
  end
21
24
 
22
25
  get '/failed' do
23
- #placeholder
24
- erb :index
26
+ erb :failed
25
27
  end
26
28
 
27
29
  get '/scheduled' do
28
- #placeholder
29
30
  erb :scheduled
30
31
  end
32
+
33
+ get '/redis-data' do
34
+ redis = Redis.new
35
+
36
+ (1..redis.mget('data')[0].to_i).to_a.sample.to_s
37
+ end
@@ -0,0 +1,109 @@
1
+ $(document).ready(function() {
2
+ var tab = $(location).attr('href').split('/').pop();
3
+ var $active = $('a[href=' + tab + ']');
4
+ $active.css('background', '#a2a2a2');
5
+ $active.css('color', '#fff');
6
+
7
+ setInterval(getDataFromRedis, 5000);
8
+
9
+ var chart = new CanvasJS.Chart('chart_container', {
10
+ title: {
11
+ text: 'Overview',
12
+ fontSize: 24,
13
+ },
14
+ axisX: {
15
+ reversed: true,
16
+ gridColor: 'Silver',
17
+ tickColor: 'silver',
18
+ animationEnabled: true,
19
+ title: 'Time ago (s)',
20
+ // minimum: 0,
21
+ maximum: 65
22
+ },
23
+ toolTip: {
24
+ shared: true
25
+ },
26
+ theme: "theme2",
27
+ axisY: {
28
+ gridColor: "Silver",
29
+ tickColor: "silver"
30
+ },
31
+ legend:{
32
+ verticalAlign: "center",
33
+ horizontalAlign: "right"
34
+ },
35
+ data: [{
36
+ type: "line",
37
+ showInLegend: true,
38
+ lineThickness: 2,
39
+ name: "Queued Jobs",
40
+ markerType: "square",
41
+ color: "#F08080",
42
+ dataPoints: [
43
+ { x: '0', y: 510 },
44
+ { x: '5', y: 570 },
45
+ { x: '10', y: 510 },
46
+ { x: '15', y: 510 },
47
+ { x: '20', y: 610 },
48
+ { x: '25', y: 510 },
49
+ { x: '30', y: 510 },
50
+ { x: '35', y: 510 },
51
+ { x: '40', y: 510 },
52
+ { x: '45', y: 910 },
53
+ { x: '50', y: 510 },
54
+ { x: '55', y: 710 },
55
+ { x: '60', y: 510 },
56
+ ]
57
+ },
58
+ {
59
+ type: "line",
60
+ showInLegend: true,
61
+ name: "Finished Jobs",
62
+ color: "#20B2AA",
63
+ lineThickness: 2,
64
+
65
+ dataPoints: [
66
+ { x: '0', y: 430 },
67
+ { x: '5', y: 580 },
68
+ { x: '10', y: 420 },
69
+ { x: '15', y: 110 },
70
+ { x: '20', y: 180 },
71
+ { x: '25', y: 900 },
72
+ { x: '30', y: 510 },
73
+ { x: '35', y: 510 },
74
+ { x: '40', y: 510 },
75
+ { x: '45', y: 510 },
76
+ { x: '50', y: 670 },
77
+ { x: '55', y: 990 },
78
+ { x: '60', y: 240 },
79
+ ]
80
+ }
81
+
82
+
83
+ ],
84
+ legend: {
85
+ cursor: "pointer",
86
+ itemclick: function(e){
87
+ if (typeof(e.dataSeries.visible) === "undefined" || e.dataSeries.visible) {
88
+ e.dataSeries.visible = false;
89
+ }
90
+ else{
91
+ e.dataSeries.visible = true;
92
+ }
93
+ chart.render();
94
+ }
95
+ }
96
+ });
97
+
98
+ chart.render();
99
+ });
100
+
101
+ function getDataFromRedis() {
102
+ $.ajax({
103
+ url: '/redis-data',
104
+ data: 'something',
105
+ success: function(data) {
106
+ $('.data').text(data);
107
+ }
108
+ });
109
+ }
@@ -2,7 +2,7 @@
2
2
 
3
3
  body {
4
4
  font-family: Arial, sans-serif;
5
- background: #FFD252;
5
+ background: #f2f2f2;
6
6
  }
7
7
 
8
8
  header {
@@ -13,6 +13,12 @@ header {
13
13
  background: linear-gradient(to bottom, #3A0E40, #E739FF);
14
14
  }
15
15
 
16
+ section {
17
+ width: 1200px;
18
+ padding-bottom: 100px;
19
+ margin: 0 auto;
20
+ }
21
+
16
22
  footer {
17
23
  position: fixed;
18
24
  bottom: 0;
@@ -30,24 +36,34 @@ nav {
30
36
  background: #fff;
31
37
  }
32
38
 
33
- nav li {
34
- display: inline-block;
35
- font-size: 20px;
36
- padding: 10px 0 10px 0;
37
- margin-left: 20px;
38
- color: #000;
39
- }
40
-
41
39
  nav a {
42
40
  display: inline-block;
43
- width: 100px;
44
- padding: 20px;
41
+ width: 100%;
42
+ padding: 10px;
45
43
  text-align: center;
46
- text-decoration: none;
47
44
  border-radius: 5px;
48
- border: 3px solid #E739FF;
45
+ color: #000;
46
+ background: #cecece;
47
+ }
48
+
49
+ nav a:hover {
49
50
  color: #fff;
50
- background: #A016B2;
51
+ background: #a2a2a2;
52
+ }
53
+
54
+ .table {
55
+ width: 1200px;
56
+ margin-top: 100px;
57
+ border: 1px solid #c5c5c5;
58
+ /*border-radius: 5px;*/
59
+ }
60
+
61
+ .last_row {
62
+ border-top: 5px solid #a1a1a1;
63
+ }
64
+
65
+ .data {
66
+ width: 200px;
51
67
  }
52
68
 
53
69
  #statistics {
@@ -1,32 +1,49 @@
1
- <html>
2
- <head>
3
- <title>Workerholic Overview</title>
4
- <link href="https://fonts.googleapis.com/css?family=Dosis" rel="stylesheet">
5
- <link href='stylesheets/application.css' rel='stylesheet'>
6
- </head>
1
+ <table class='table'>
2
+ <thead>
3
+ <tr>
4
+ <th>Class</th>
5
+ <th>Enqueued</th>
6
+ <th>Failed</th>
7
+ <th>Completed</th>
8
+ <th>Total</th>
9
+ </tr>
10
+ </thead>
7
11
 
8
- <body>
9
- <header>
10
- Workerholic
11
- </header>
12
- <nav>
13
- <ul>
14
- <li><a href='/'>Overview</a></li>
15
- <li><a href='/details'>Job Details</a></li>
16
- <li><a href='/queues'>Queues</a></li>
17
- <li><a href='/queues'>Workers</a></li>
18
- <li><a href='/what'>Failed</a></li>
19
- <li><a href='/what'>Scheduled</a></li>
20
- </ul>
21
- </nav>
22
-
23
- <div id="statistics">
24
- <h2>Your current active queues:</h2>
25
- <p>JobTestFast: 1,234</p>
26
- <p>JobtestSlow: 2,144,822</p>
27
- <p>GetPrimes: 102,891</p>
28
- <p>Total: 2,248,947</p>
29
- </div>
30
-
31
- </body>
32
- </html>
12
+ <tbody>
13
+ <tr>
14
+ <td>JobTestFast</td>
15
+ <td>1,833,222</td>
16
+ <td>171,882</td>
17
+ <td>22,198,122</td>
18
+ <td>24,123,233</td>
19
+ </tr>
20
+ <tr>
21
+ <td>JobTestSlow</td>
22
+ <td>1,833,222</td>
23
+ <td>171,882</td>
24
+ <td>22,198,122</td>
25
+ <td>24,123,233</td>
26
+ </tr>
27
+ <tr>
28
+ <td>GetPrime</td>
29
+ <td>1,833,222</td>
30
+ <td>171,882</td>
31
+ <td>22,198,122</td>
32
+ <td>24,123,233</td>
33
+ </tr>
34
+ <tr>
35
+ <td>SendWelcomeEmail</td>
36
+ <td>1,833,222</td>
37
+ <td>171,882</td>
38
+ <td>22,198,122</td>
39
+ <td>24,123,233</td>
40
+ </tr>
41
+ <tr class='last_row'>
42
+ <th>Total:</td>
43
+ <td>1,833,222</td>
44
+ <td>171,882</td>
45
+ <td>22,198,122</td>
46
+ <td>24,123,233</td>
47
+ </tr>
48
+ </tbody>
49
+ </table>
@@ -0,0 +1,27 @@
1
+ <table class='table'>
2
+ <thead>
3
+ <tr>
4
+ <th>Queue Name</th>
5
+ <th>Class</th>
6
+ <th>Job ID</th>
7
+ <th>Time</th>
8
+ <th>Error</th>
9
+ </tr>
10
+ </thead>
11
+
12
+ <tr>
13
+ <td>workerholic:queue:main</td>
14
+ <td>JobTestFast</td>
15
+ <td>22</td>
16
+ <td>07-26-2017 18:21:44</td>
17
+ <td>ArgumentError: Wrong number of arguments. (0 for 2)</td>
18
+ </tr>
19
+
20
+ <tr>
21
+ <td>workerholic:queue:main</td>
22
+ <td>JobTestFast</td>
23
+ <td>22</td>
24
+ <td>07-26-2017 18:21:44</td>
25
+ <td>ArgumentError: ....</td>
26
+ </tr>
27
+ </table>
data/web/views/index.erb CHANGED
@@ -1,35 +1,40 @@
1
- <html>
2
- <head>
3
- <title>Workerholic Overview</title>
4
- <link href="https://fonts.googleapis.com/css?family=Dosis" rel="stylesheet">
5
- <link href='stylesheets/application.css' rel='stylesheet'>
6
- </head>
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
7
 
8
- <body>
9
- <header>
10
- Workerholic
11
- </header>
12
- <nav>
13
- <ul>
14
- <li><a href='/'>Overview</a></li>
15
- <li><a href='/details'>Job Details</a></li>
16
- <li><a href='/placehold'>Queues</a></li>
17
- <li><a href='/workers'>Workers</a></li>
18
- <li><a href='/what'>Failed</a></li>
19
- <li><a href='/what'>Scheduled</a></li>
20
- </ul>
21
- </nav>
8
+ <table class='table is-striped'>
9
+ <thead>
10
+ <tr>
11
+ <th>Category</th>
12
+ <th>Count</th>
13
+ </tr>
14
+ </thead>
15
+ <tbody>
16
+ <tr>
17
+ <td>Finished Jobs</td>
18
+ <td class='data'>10,000,000</td>
19
+ </tr>
20
+ <tr>
21
+ <td>Queued Jobs</td>
22
+ <td class='data'>1,000,000</td>
23
+ </tr>
24
+ <tr>
25
+ <td>Failed Jobs</td>
26
+ <td class='data'>1,000,000</td>
27
+ </tr>
28
+ <tr>
29
+ <td>Number of Queues</td>
30
+ <td>3</td>
31
+ </tr>
32
+ <tr>
33
+ <td>Number of Workers</td>
34
+ <td>25</td>
35
+ </tr>
36
+ </tbody>
37
+ </table>
22
38
 
23
- <div id="statistics">
24
- <h2>Your current jobs overview</h2>
25
- <p id="completed">Finished Jobs: 0</p>
26
- <p>Jobs in queue: 100,000,000</p>
27
- <p id="failed">Jobs failed: 10,000,000</p>
28
- </div>
29
-
30
- <footer>
31
- <p>&copy; 2017 Workerholic. All rights reserved.</p>
32
- </footer>
33
-
34
- </body>
35
- </html>
39
+ <div id="chart_container" style="height: 300px; width: 100%">
40
+ </div>
@@ -0,0 +1,36 @@
1
+ <html>
2
+ <head>
3
+ <title>Workerholic Overview</title>
4
+ <link href="https://fonts.googleapis.com/css?family=Dosis" rel="stylesheet">
5
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.4.4/css/bulma.css" rel="stylesheet">
6
+ <link href='stylesheets/application.css' rel='stylesheet'>
7
+ <script src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>
8
+ <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
9
+ <script src="javascripts/application.js"></script>
10
+ </head>
11
+
12
+ <body>
13
+ <header>
14
+ Workerholic
15
+ </header>
16
+
17
+ <nav>
18
+ <ul class='columns'>
19
+ <li class='column'><a href='overview'>Overview</a></li>
20
+ <li class='column'><a href='details'>Job Details</a></li>
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>
24
+ <li class='column'><a href='scheduled'>Scheduled</a></li>
25
+ </ul>
26
+ </nav>
27
+
28
+ <section>
29
+ <%= yield %>
30
+ </section>
31
+
32
+ <footer>
33
+ <p>&copy; 2017 Workerholic. All rights reserved.</p>
34
+ </footer>
35
+ </body>
36
+ </html>
@@ -0,0 +1,31 @@
1
+ <table class='table'>
2
+ <thead>
3
+ <tr>
4
+ <th>Queue Name</th>
5
+ <th>Job Load</th>
6
+ <th>Worker Count</th>
7
+ <th>Jobs Processed per second</th>
8
+ </tr>
9
+ </thead>
10
+
11
+ <tr>
12
+ <td>workerholic:queue:main</td>
13
+ <td>485,981</td>
14
+ <td>12</td>
15
+ <td>1442</td>
16
+ </tr>
17
+
18
+ <tr>
19
+ <td>workerholic:queue:api</td>
20
+ <td>75,912,999</td>
21
+ <td>13</td>
22
+ <td>1233</td>
23
+ </tr>
24
+
25
+ <tr class='last_row'>
26
+ <th>Total:</td>
27
+ <td>76,984,123</td>
28
+ <td>25</td>
29
+ <td>2675</td>
30
+ </tr>
31
+ </table>
@@ -0,0 +1,27 @@
1
+ <table class='table'>
2
+ <thead>
3
+ <tr>
4
+ <th>Class</th>
5
+ <th>Execute on</th>
6
+ <th>Arguments</th>
7
+ </tr>
8
+ </thead>
9
+
10
+ <tr>
11
+ <td>GithubAPIWrapper</td>
12
+ <td>07-29-17 00:00:00</td>
13
+ <td>{ username: 'tim-lee92', repo: 'workerholic' }</td>
14
+ </tr>
15
+
16
+ <tr>
17
+ <td>GithubAPIWrapper</td>
18
+ <td>07-29-17 00:00:00</td>
19
+ <td>{ username: 'tim-lee92', repo: 'workerholic' }</td>
20
+ </tr>
21
+
22
+ <tr>
23
+ <td>GithubAPIWrapper</td>
24
+ <td>07-29-17 00:00:00</td>
25
+ <td>{ username: 'tim-lee92', repo: 'workerholic' }</td>
26
+ </tr>
27
+ </table>