workerholic 0.0.14 → 0.0.15

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.
@@ -8,6 +8,17 @@ module Workerholic
8
8
  storage.push(namespace, serialized_job_stats)
9
9
  end
10
10
 
11
+ def self.save_processes_memory_usage
12
+ PIDS.each do |pid|
13
+ size = `ps -p #{Process.pid} -o pid=,rss=`.scan(/\d+/).last
14
+ storage.hash_set('workerholic:stats:memory:processes', pid, size)
15
+ end
16
+ end
17
+
18
+ def self.delete_memory_stats
19
+ storage.delete('workerholic:stats:memory:processes')
20
+ end
21
+
11
22
  class << self
12
23
  private
13
24
 
@@ -13,6 +13,18 @@ module Workerholic
13
13
  end
14
14
  end
15
15
 
16
+ def hash_set(key, field, value, retry_delay = 5)
17
+ execute(retry_delay) { |conn| conn.hset(key, field, value) }
18
+ end
19
+
20
+ def hash_get(key, field, retry_delay = 5)
21
+ execute(retry_delay) { |conn| conn.hget(key, field) }
22
+ end
23
+
24
+ def delete(key, retry_delay = 5)
25
+ execute(retry_delay) { |conn| conn.del(key) }
26
+ end
27
+
16
28
  def list_length(key, retry_delay = 5)
17
29
  execute(retry_delay) { |conn| conn.llen(key) }
18
30
  end
@@ -42,6 +54,14 @@ module Workerholic
42
54
  execute(retry_delay) { |conn| conn.zcount(key, 0, '+inf') }
43
55
  end
44
56
 
57
+ def sorted_set_members(key, retry_delay = 5)
58
+ execute(retry_delay) { |conn| conn.zrange(key, 0, -1) }
59
+ end
60
+
61
+ def sorted_set_members_count(key, retry_delay = 5)
62
+ execute(retry_delay) { |conn| conn.zcard(key) }
63
+ end
64
+
45
65
  def keys_count(namespace, retry_delay = 5)
46
66
  execute(retry_delay) { |conn| conn.keys(namespace + ':*').size }
47
67
  end
@@ -52,25 +72,24 @@ module Workerholic
52
72
  execute(retry_delay) { |conn| conn.scan(0, match: queue_name_pattern).last }
53
73
  end
54
74
 
55
- def available_keys(retry_delay = 5)
56
- execute(retry_delay) { |conn| conn.keys('workerholic:stats:*') }
75
+ def get_keys_for_namespace(namespace, retry_delay = 5)
76
+ execute(retry_delay) { |conn| conn.keys(namespace) }
57
77
  end
58
78
 
59
- def keys_for_namespace(namespace, retry_delay = 5)
60
- execute(retry_delay) { |conn| conn.keys('workerholic:stats:' + namespace + ':*') }
79
+ def get_all_elements_from_list(key, retry_delay = 5)
80
+ execute(retry_delay) { |conn| conn.lrange(key, 0, -1) }
61
81
  end
62
82
 
63
- def peek_namespace(key, retry_delay = 5)
64
- execute(retry_delay) { |conn| conn.lrange(key, 0, -1) }
83
+ def hash_get(key, field, retry_delay = 5)
84
+ execute(retry_delay) { |conn| conn.hget(key, field) }
65
85
  end
66
86
 
67
- def peek_namespaces(keys, retry_delay = 5)
68
- execute(retry_delay) do |conn|
69
- keys.select do |namespace|
70
- full_namespace = 'workerholic:stats:' + namespace
71
- conn.keys(full_namespace + ':*').size > 0
72
- end
73
- end
87
+ def hash_get_all(key, retry_delay = 5)
88
+ execute(retry_delay) { |conn| conn.hgetall(key) }
89
+ end
90
+
91
+ def hash_keys(namespace, retry_delay = 5)
92
+ execute(retry_delay) { |conn| conn.hkeys(namespace) }
74
93
  end
75
94
 
76
95
  class RedisCannotRecover < Redis::CannotConnectError; end
@@ -1,3 +1,3 @@
1
1
  module Workerholic
2
- VERSION = '0.0.14'
2
+ VERSION = '0.0.15'
3
3
  end
Binary file
@@ -3,6 +3,7 @@ ANOTHER_TEST_QUEUE = 'workerholic:testing:queue:another_test_queue'
3
3
  BALANCER_TEST_QUEUE = 'workerholic:testing:queue:balancer_test_queue'
4
4
  ANOTHER_BALANCER_TEST_QUEUE = 'workerholic:testing:queue:another_balancer_test_queue'
5
5
  TEST_SCHEDULED_SORTED_SET = 'workerholic:testing:scheduled_jobs'
6
+ HASH_TEST = 'workerholic:testing:hash_test'
6
7
 
7
8
  def expect_during(duration_in_secs, target)
8
9
  timeout = Time.now.to_f + duration_in_secs
@@ -20,7 +20,7 @@ class FirstJobBalancerTest
20
20
  include Workerholic::Job
21
21
  job_options queue_name: BALANCER_TEST_QUEUE
22
22
 
23
- def perform(str, num)
23
+ def perform(str, n)
24
24
  str
25
25
  end
26
26
  end
@@ -29,8 +29,15 @@ class SecondJobBalancerTest
29
29
  include Workerholic::Job
30
30
  job_options queue_name: ANOTHER_BALANCER_TEST_QUEUE
31
31
 
32
- def perform(str, num)
32
+ def perform(str, n)
33
33
  str
34
34
  end
35
35
  end
36
36
 
37
+ class DelayedJobTest
38
+ include Workerholic::Job
39
+
40
+ def perform(str)
41
+ str
42
+ end
43
+ end
@@ -31,6 +31,17 @@ describe 'enqueuing jobs to Redis' do
31
31
  expect(job_from_redis.to_hash).to eq(expected_job.to_hash)
32
32
  end
33
33
 
34
+ xit 'enqueues a delayed job in redis' do
35
+ DelayedJobTest.new.perform_delayed(100, 'test job')
36
+ serialized_job = redis.lpop(TEST_QUEUE)
37
+ job_from_redis = Workerholic::JobSerializer.deserialize(serialized_job)
38
+
39
+ expected_job = Workerholic::JobWrapper.new(klass: SimpleJobTest, arguments: ['test job'], wrapper: SimpleJobTest)
40
+ expected_job.statistics.enqueued_at = job_from_redis.statistics.enqueued_at
41
+
42
+ expect(job_from_redis.to_hash).to eq(expected_job.to_hash)
43
+ end
44
+
34
45
  it 'enqueues a job with the right statistics' do
35
46
  SimpleJobTest.new.perform_async('test_job')
36
47
  serialized_job = redis.lpop(TEST_QUEUE)
@@ -50,5 +61,11 @@ describe 'enqueuing jobs to Redis' do
50
61
  it 'raises an error when wrong number of arguments is specified to perform_async' do
51
62
  expect { SimpleJobTest.new.perform_async(1, 2, 3) }.to raise_error(ArgumentError)
52
63
  end
64
+
65
+ it 'raises an ArgumentError if perform_delayed first argument is not of Numeric type' do
66
+ job = DelayedJobTest.new
67
+
68
+ expect { job.perform_delayed('wrong type', 'test arg') }.to raise_error(ArgumentError)
69
+ end
53
70
  end
54
71
  end
@@ -2,7 +2,6 @@ require_relative 'spec_helper'
2
2
 
3
3
  class SimpleJobTestWithError
4
4
  include Workerholic::Job
5
- job_options queue_name: TEST_SCHEDULED_SORTED_SET
6
5
 
7
6
  def perform
8
7
  raise Exception
@@ -34,13 +33,14 @@ describe Workerholic::JobProcessor do
34
33
  end
35
34
 
36
35
  it 'does not raise an error when processing a job with error' do
37
- serialized_job = Workerholic::JobSerializer.serialize({
38
- klass: SimpleJobTestWithError,
39
- arguments: [],
40
- statistics: Workerholic::JobStatistics.new.to_hash
41
- })
36
+ serialized_job = Workerholic::JobSerializer.serialize(
37
+ klass: SimpleJobTestWithError,
38
+ arguments: [],
39
+ statistics: Workerholic::JobStatistics.new.to_hash
40
+ )
42
41
 
43
42
  job_processor = Workerholic::JobProcessor.new(serialized_job)
43
+ allow(job_processor).to receive(:retry_job)
44
44
 
45
45
  expect { job_processor.process }.not_to raise_error
46
46
  end
@@ -52,10 +52,10 @@ describe Workerholic::JobProcessor do
52
52
  statistics: Workerholic::JobStatistics.new.to_hash
53
53
  }
54
54
  serialized_job = Workerholic::JobSerializer.serialize(job)
55
+ job_processor = Workerholic::JobProcessor.new(serialized_job)
55
56
 
56
- allow(Workerholic::JobRetry).to receive(:new)
57
- expect(Workerholic::JobRetry).to receive(:new)
57
+ expect(job_processor).to receive(:retry_job)
58
58
 
59
- Workerholic::JobProcessor.new(serialized_job).process
59
+ job_processor.process
60
60
  end
61
61
  end
@@ -15,7 +15,7 @@ describe Workerholic::JobRetry do
15
15
  Workerholic::JobRetry.new(
16
16
  job: job,
17
17
  sorted_set: Workerholic::SortedSet.new(TEST_SCHEDULED_SORTED_SET)
18
- )
18
+ ).retry
19
19
 
20
20
  expect(job.retry_count).to eq(1)
21
21
  end
@@ -26,7 +26,7 @@ describe Workerholic::JobRetry do
26
26
  Workerholic::JobRetry.new(
27
27
  job: job,
28
28
  sorted_set: Workerholic::SortedSet.new(TEST_SCHEDULED_SORTED_SET)
29
- )
29
+ ).retry
30
30
 
31
31
  expect((job.execute_at - Time.now.to_f).ceil).to eq(30)
32
32
  end
@@ -37,7 +37,7 @@ describe Workerholic::JobRetry do
37
37
  Workerholic::JobRetry.new(
38
38
  job: job,
39
39
  sorted_set: Workerholic::SortedSet.new(TEST_SCHEDULED_SORTED_SET)
40
- )
40
+ ).retry
41
41
 
42
42
  serialized_job = Workerholic::JobSerializer.serialize(job)
43
43
 
@@ -50,7 +50,7 @@ describe Workerholic::JobRetry do
50
50
  Workerholic::JobRetry.new(
51
51
  job: job,
52
52
  sorted_set: Workerholic::SortedSet.new(TEST_SCHEDULED_SORTED_SET)
53
- )
53
+ ).retry
54
54
 
55
55
  expect(redis.exists(TEST_SCHEDULED_SORTED_SET)).to eq(false)
56
56
  end
@@ -1,16 +1,13 @@
1
1
  require_relative 'spec_helper'
2
2
 
3
- class SimpleDelayedJobTest
4
- include Workerholic::Job
5
- job_options queue_name: TEST_SCHEDULED_SORTED_SET
6
-
7
- def perform(n, s)
8
- s
3
+ describe Workerholic::JobScheduler do
4
+ let(:scheduler) do
5
+ Workerholic::JobScheduler.new(
6
+ sorted_set: Workerholic::SortedSet.new(TEST_SCHEDULED_SORTED_SET),
7
+ queue_name: TEST_QUEUE
8
+ )
9
9
  end
10
- end
11
10
 
12
- describe Workerholic::JobScheduler do
13
- let(:scheduler) { Workerholic::JobScheduler.new(set_name: TEST_SCHEDULED_SORTED_SET, queue_name: TEST_QUEUE) }
14
11
  let(:redis) { Redis.new }
15
12
 
16
13
  context 'with non-empty set' do
@@ -47,18 +44,4 @@ describe Workerholic::JobScheduler do
47
44
  expect(scheduler.queue.dequeue).to eq(serialized_job)
48
45
  end
49
46
  end
50
-
51
- context 'with delayed job option specified' do
52
- it 'adds delayed job to the scheduled sorted set' do
53
- SimpleDelayedJobTest.new.perform_delayed(2, 'test arg')
54
-
55
- expect(scheduler.sorted_set.empty?).to eq(false)
56
- end
57
-
58
- it 'raises an ArgumentError if perform_delayed first argument is not of Numeric type' do
59
- job = SimpleDelayedJobTest.new
60
-
61
- expect { job.perform_delayed("wrong type", 'test arg') }.to raise_error(ArgumentError)
62
- end
63
- end
64
47
  end
data/spec/spec_helper.rb CHANGED
@@ -20,6 +20,10 @@ RSpec.configure do |config|
20
20
  config.shared_context_metadata_behavior = :apply_to_host_groups
21
21
 
22
22
  config.before do
23
- Redis.new.del(TEST_QUEUE, ANOTHER_TEST_QUEUE, BALANCER_TEST_QUEUE, ANOTHER_BALANCER_TEST_QUEUE, TEST_SCHEDULED_SORTED_SET)
23
+ Redis.new.del(TEST_QUEUE, ANOTHER_TEST_QUEUE, BALANCER_TEST_QUEUE, ANOTHER_BALANCER_TEST_QUEUE, TEST_SCHEDULED_SORTED_SET, HASH_TEST)
24
+ end
25
+
26
+ config.after do
27
+ Redis.new.del(TEST_QUEUE, ANOTHER_TEST_QUEUE, BALANCER_TEST_QUEUE, ANOTHER_BALANCER_TEST_QUEUE, TEST_SCHEDULED_SORTED_SET, HASH_TEST)
24
28
  end
25
29
  end
data/spec/storage_spec.rb CHANGED
@@ -68,6 +68,25 @@ describe Workerholic::Storage do
68
68
 
69
69
  expect(storage.fetch_queue_names).to match_array([queue_name, ANOTHER_TEST_QUEUE])
70
70
  end
71
+
72
+ it 'sets k and a value to a hash in redis' do
73
+ storage.hash_set(HASH_TEST, 'key_test', 1234)
74
+
75
+ expect(redis.hget(HASH_TEST, 'key_test')).to eq('1234')
76
+ end
77
+
78
+ it 'gets the value for a given key of a hash in redis' do
79
+ redis.hset(HASH_TEST, 'key_test', 1234)
80
+
81
+ expect(storage.hash_get(HASH_TEST, 'key_test')).to eq('1234')
82
+ end
83
+
84
+ it 'deletes a key from redis' do
85
+ redis.set(TEST_QUEUE, 'something')
86
+ storage.delete(TEST_QUEUE)
87
+
88
+ expect(redis.exists(TEST_QUEUE)).to eq(false)
89
+ end
71
90
  end
72
91
 
73
92
  context 'with Redis not running' do
@@ -16,8 +16,8 @@ describe Workerholic::WorkerBalancer do
16
16
  it 'fetches queues' do
17
17
  allow(Workerholic::WorkerBalancer.new).to receive(:fetch_queues).and_return(TESTED_QUEUES)
18
18
 
19
- manager = Workerholic::WorkerBalancer.new(workers: [])
19
+ balancer = Workerholic::WorkerBalancer.new(workers: [])
20
20
 
21
- expect(manager.queues.map(&:name)).to match_array(TESTED_QUEUES)
21
+ expect(balancer.queues.map(&:name)).to match_array(TESTED_QUEUES)
22
22
  end
23
23
  end
data/web/application.rb CHANGED
@@ -11,12 +11,12 @@ class WorkerholicWeb < Sinatra::Base
11
11
  end
12
12
 
13
13
  get '/overview' do
14
- erb :index
14
+ erb :overview
15
15
  end
16
16
 
17
17
  get '/details' do
18
- completed_jobs = Workerholic::StatsAPI.job_statistics( {category: 'completed_jobs', count_only: true} )
19
- failed_jobs = Workerholic::StatsAPI.job_statistics( {category: 'failed_jobs', count_only: true} )
18
+ completed_jobs = Workerholic::StatsAPI.job_statistics(category: 'completed_jobs', count_only: true)
19
+ failed_jobs = Workerholic::StatsAPI.job_statistics(category: 'failed_jobs', count_only: true)
20
20
 
21
21
  @job_stats = {}
22
22
  @completed_total = 0
@@ -28,7 +28,11 @@ class WorkerholicWeb < Sinatra::Base
28
28
  end
29
29
 
30
30
  failed_jobs.each do |job|
31
- @job_stats[job[0]].merge( { failed: job[1] })
31
+ if @job_stats[job[0]]
32
+ @job_stats[job[0]].merge({ failed: job[1] })
33
+ else
34
+ @job_stats[job[0]] = { failed: job[1] }
35
+ end
32
36
  @failed_total += job[1]
33
37
  end
34
38
 
@@ -45,37 +49,27 @@ class WorkerholicWeb < Sinatra::Base
45
49
  erb :queues
46
50
  end
47
51
 
48
- # get '/workers' do
49
- # erb :workers
50
- # end
51
- #
52
- # get '/failed' do
53
- # erb :failed
54
- # end
55
- #
56
- # get '/scheduled' do
57
- # erb :scheduled
58
- # end
59
-
60
52
  get '/overview-data' do
61
53
  JSON.generate({
62
54
  completed_jobs: Workerholic::StatsAPI.job_statistics( {category: 'completed_jobs', count_only: true} ),
63
55
  failed_jobs: Workerholic::StatsAPI.job_statistics( {category: 'failed_jobs', count_only: true} ),
64
56
  queued_jobs: Workerholic::StatsAPI.queued_jobs,
65
- workers_count: Workerholic.workers_count
57
+ workers_count: Workerholic.workers_count,
58
+ # memory_usage: Workerholic::StatsAPI.memory_usage
66
59
  })
67
60
  end
68
61
 
69
- get '/detail-data' do
62
+ get '/details-data' do
70
63
  JSON.generate({
71
64
  completed_jobs: Workerholic::StatsAPI.job_statistics( {category: 'completed_jobs', count_only: true} ),
72
65
  failed_jobs: Workerholic::StatsAPI.job_statistics( {category: 'failed_jobs', count_only: true} )
73
66
  })
74
67
  end
75
68
 
76
- get '/queue-data' do
69
+ get '/queues-data' do
77
70
  JSON.generate({
78
71
  queued_jobs: Workerholic::StatsAPI.queued_jobs
79
72
  })
80
73
  end
74
+
81
75
  end
@@ -1,270 +1,316 @@
1
- var queuedJobsCountHistory = [];
2
- var failedJobsCountHistory = [];
3
- var jobsCompletedHistory = [];
1
+ var App = {
2
+ queuedJobsCountHistory: [],
3
+ failedJobsCountHistory: [],
4
+ jobsCompletedHistory: [],
5
+ totalMemoryHistory: [],
6
+ tab: null,
7
+ getOverviewData: function() {
8
+ $.ajax({
9
+ url: '/overview-data',
10
+ context: this,
11
+ success: function(data) {
12
+ var deserializedData = JSON.parse(data);
4
13
 
5
- $(document).ready(function() {
6
- var tab = $(location).attr('href').split('/').pop();
7
- var $active = $('a[href=' + tab + ']');
14
+ var completedJobs = deserializedData.completed_jobs.reduce(function(sum, subArray) {
15
+ return sum + subArray[1];
16
+ }, 0);
8
17
 
9
- $active.css('background', '#a2a2a2');
10
- $active.css('color', '#fff');
18
+ var failedJobsCount= deserializedData.failed_jobs.reduce(function(sum, subArray) {
19
+ return sum + subArray[1];
20
+ }, 0);
11
21
 
12
- if (tab === 'overview') {
13
- getOverviewData();
22
+ var queuedJobs = deserializedData.queued_jobs;
14
23
 
15
- setInterval(function() {
16
- getOverviewData();
17
- }, 5000);
18
- }
19
-
20
- if (tab === 'queues') {
21
- setInterval(function() {
22
- getQueueData();
23
- }, 5000);
24
- }
24
+ var queuedJobsCount = queuedJobs.reduce(function(sum, queue) {
25
+ return sum + queue[1];
26
+ }, 0);
25
27
 
26
- if (tab === 'details') {
27
- setInterval(function() {
28
- getDetailData();
29
- }, 1000);
30
- }
31
- });
28
+ // var totalMemory = deserializedData.memory_usage ...
32
29
 
33
- function getOverviewData() {
34
- $.ajax({
35
- url: '/overview-data',
36
- success: function(data) {
37
- var deserializedData = JSON.parse(data);
30
+ this.queuedJobsCountHistory.unshift(queuedJobsCount);
31
+ this.failedJobsCountHistory.unshift(failedJobsCount);
32
+ this.jobsCompletedHistory.unshift(completedJobs);
33
+ // totalMemoryHistory.unshift(totalMemory); Waiting for data
38
34
 
39
- var completedJobs = deserializedData.completed_jobs.reduce(function(sum, subArray) {
40
- return sum + subArray[1];
41
- }, 0);
35
+ if (this.queuedJobsCountHistory.length > 13) {
36
+ this.queuedJobsCountHistory.pop();
37
+ this.failedJobsCountHistory.pop();
38
+ this.jobsCompletedHistory.pop();
39
+ this.totalMemoryHistory.pop();
40
+ }
42
41
 
43
- var failedJobsCount= deserializedData.failed_jobs.reduce(function(sum, subArray) {
44
- return sum + subArray[1];
45
- }, 0);
42
+ this.drawChart();
46
43
 
47
- var queuedJobs = deserializedData.queued_jobs;
44
+ var workersCount = deserializedData.workers_count;
48
45
 
49
- var queuedJobsCount = queuedJobs.reduce(function(sum, queue) {
50
- return sum + queue[1];
51
- }, 0);
52
-
53
- queuedJobsCountHistory.unshift(queuedJobsCount);
54
- failedJobsCountHistory.unshift(failedJobsCount);
55
- jobsCompletedHistory.unshift(completedJobs);
56
-
57
- if (queuedJobsCountHistory.length > 13) {
58
- queuedJobsCountHistory.pop();
59
- failedJobsCountHistory.pop();
60
- jobsCompletedHistory.pop();
46
+ $('.completed_jobs').text(completedJobs);
47
+ $('.failed_jobs').text(failedJobsCount);
48
+ $('.queue_count').text(queuedJobs.length);
49
+ $('.queued_jobs_count').text(queuedJobsCount);
50
+ $('.workers_count').text(workersCount);
61
51
  }
52
+ });
53
+ },
54
+ getQueueData: function() {
55
+ $.ajax({
56
+ url: '/queues-data',
57
+ success: function(data) {
58
+ var deserializedData = JSON.parse(data);
59
+ var queuedJobs = deserializedData.queued_jobs;
60
+ var total = 0;
62
61
 
63
- drawChart();
64
-
65
- var workersCount = deserializedData.workers_count;
62
+ for (var i = 0; i < queuedJobs.length; i++) {
63
+ $('#queue_name_' + queuedJobs[i][0].split(':').pop()).text(queuedJobs[i][0]);
64
+ $('#queue_count_' + queuedJobs[i][0].split(':').pop()).text(queuedJobs[i][1]);
65
+ total = total + queuedJobs[i][1];
66
+ }
66
67
 
67
- $('.completed_jobs').text(completedJobs);
68
- $('.failed_jobs').text(failedJobsCount);
69
- $('.queue_count').text(queuedJobs.length);
70
- $('.queued_jobs_count').text(queuedJobsCount);
71
- $('.workers_count').text(workersCount);
72
- }
73
- });
74
- }
75
-
76
- function getQueueData() {
77
- $.ajax({
78
- url: '/queue-data',
79
- success: function(data) {
80
- var deserializedData = JSON.parse(data);
81
- var queuedJobs = deserializedData.queued_jobs;
82
- var total = 0;
83
-
84
- for (var i = 0; i < queuedJobs.length; i++) {
85
- $('#queue_name_' + queuedJobs[i][0].split(':').pop()).text(queuedJobs[i][0]);
86
- $('#queue_count_' + queuedJobs[i][0].split(':').pop()).text(queuedJobs[i][1]);
87
- total = total + queuedJobs[i][1];
68
+ $('#queue_total').text(total);
88
69
  }
70
+ });
71
+ },
72
+ getDetailData: function() {
73
+ $.ajax({
74
+ url: '/details-data',
75
+ success: function(data) {
76
+ var deserializedData = JSON.parse(data);
77
+ var completedJobs = deserializedData.completed_jobs;
78
+ var failedJobs = deserializedData.failed_jobs;
79
+ var completedTotal = 0;
80
+ var failedTotal = 0;
89
81
 
90
- $('#queue_total').text(total);
91
- }
92
- });
93
- }
94
-
95
- function getDetailData() {
96
- $.ajax({
97
- url: '/detail-data',
98
- success: function(data) {
99
- var deserializedData = JSON.parse(data);
100
- var completedJobs = deserializedData.completed_jobs;
101
- var failedJobs = deserializedData.failed_jobs;
102
- var completedTotal = 0;
103
- var failedTotal = 0;
82
+ completedJobs.forEach(function(job) {
83
+ $('#completed_' + job[0]).text(job[1]);
84
+ completedTotal = completedTotal + job[1];
85
+ });
104
86
 
105
- completedJobs.forEach(function(job) {
106
- $('#completed_' + job[0]).text(job[1]);
107
- completedTotal = completedTotal + job[1];
108
- });
87
+ failedJobs.forEach(function(job) {
88
+ $('#failed_' + job[0]).text(job[1]);
89
+ failedTotal = failedTotal + job[1];
90
+ });
109
91
 
110
- failedJobs.forEach(function(job) {
111
- $('#failed_' + job[0]).text(job[1]);
112
- failedTotal = failedTotal + job[1];
113
- });
92
+ $('#failed_total').text(failedTotal);
93
+ $('#completed_total').text(completedTotal);
94
+ }
95
+ })
96
+ },
97
+ drawChart: function() {
98
+ var processedJobsChart = new CanvasJS.Chart('jobs_processed_container', {
99
+ title: {
100
+ text: 'Jobs Processed per second',
101
+ fontFamily: 'Arial',
102
+ fontSize: 24,
103
+ },
104
+ axisX: {
105
+ reversed: true,
106
+ gridColor: 'Silver',
107
+ tickColor: 'silver',
108
+ animationEnabled: true,
109
+ title: 'Time ago (s)',
110
+ maximum: 60
111
+ },
112
+ toolTip: {
113
+ shared: true
114
+ },
115
+ theme: "theme2",
116
+ axisY: {
117
+ gridColor: "Silver",
118
+ tickColor: "silver",
119
+ title: 'Jobs per second',
120
+ },
121
+ data: [{
122
+ type: "line",
123
+ showInLegend: true,
124
+ name: "Jobs completed",
125
+ color: "blue",
126
+ 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
+ ]
143
+ }]
144
+ });
114
145
 
115
- $('#failed_total').text(failedTotal);
116
- $('#completed_total').text(completedTotal);
117
- }
118
- })
119
- }
146
+ var queuedJobsChart = new CanvasJS.Chart('queued_jobs_container', {
147
+ title: {
148
+ text: 'Queued Jobs',
149
+ fontFamily: 'Arial',
150
+ fontSize: 24,
151
+ },
152
+ axisX: {
153
+ reversed: true,
154
+ gridColor: 'Silver',
155
+ tickColor: 'silver',
156
+ animationEnabled: true,
157
+ title: 'Time ago (s)',
158
+ // minimum: 0,
159
+ maximum: 60
160
+ },
161
+ toolTip: {
162
+ shared: true
163
+ },
164
+ theme: "theme2",
165
+ axisY: {
166
+ gridColor: "Silver",
167
+ tickColor: "silver",
168
+ title: 'Jobs'
169
+ },
170
+ data: [{
171
+ type: "line",
172
+ showInLegend: true,
173
+ lineThickness: 2,
174
+ name: "Queued Jobs",
175
+ markerType: "circle",
176
+ color: "#F08080",
177
+ dataPoints: this.setDataPoints(this.queuedJobsCountHistory),
178
+ }],
179
+ });
120
180
 
121
- function drawChart() {
122
- var processedJobsChart = new CanvasJS.Chart('jobs_processed_container', {
123
- title: {
124
- text: 'Jobs Processed',
125
- fontSize: 24,
126
- },
127
- axisX: {
128
- reversed: true,
129
- gridColor: 'Silver',
130
- tickColor: 'silver',
131
- animationEnabled: true,
132
- title: 'Time ago (s)',
133
- maximum: 60
134
- },
135
- toolTip: {
136
- shared: true
137
- },
138
- theme: "theme2",
139
- axisY: {
140
- gridColor: "Silver",
141
- tickColor: "silver",
142
- title: 'Jobs'
143
- },
144
- data: [{
145
- type: "line",
146
- showInLegend: true,
147
- name: "Jobs completed",
148
- color: "blue",
149
- markerType: 'circle',
150
- lineThickness: 2,
151
- dataPoints: [
152
- { x: '0', y: jobsCompletedHistory[0] },
153
- { x: '5', y: jobsCompletedHistory[1] },
154
- { x: '10', y: jobsCompletedHistory[2] },
155
- { x: '15', y: jobsCompletedHistory[3] },
156
- { x: '20', y: jobsCompletedHistory[4] },
157
- { x: '25', y: jobsCompletedHistory[5] },
158
- { x: '30', y: jobsCompletedHistory[6] },
159
- { x: '35', y: jobsCompletedHistory[7] },
160
- { x: '40', y: jobsCompletedHistory[8] },
161
- { x: '45', y: jobsCompletedHistory[9] },
162
- { x: '50', y: jobsCompletedHistory[10] },
163
- { x: '55', y: jobsCompletedHistory[11] },
164
- { x: '60', y: jobsCompletedHistory[12] },
181
+ var failedJobsChart = new CanvasJS.Chart('failed_jobs_container', {
182
+ title: {
183
+ text: 'Failed Jobs',
184
+ fontFamily: 'Arial',
185
+ fontSize: 24,
186
+ },
187
+ axisX: {
188
+ reversed: true,
189
+ gridColor: 'Silver',
190
+ tickColor: 'silver',
191
+ animationEnabled: true,
192
+ title: 'Time ago (s)',
193
+ // minimum: 0,
194
+ maximum: 60
195
+ },
196
+ toolTip: {
197
+ shared: true
198
+ },
199
+ theme: "theme2",
200
+ axisY: {
201
+ gridColor: "Silver",
202
+ tickColor: "silver",
203
+ title: 'Jobs'
204
+ },
205
+ data: [{
206
+ type: "line",
207
+ showInLegend: true,
208
+ name: "Failed Jobs",
209
+ color: "#20B2AA",
210
+ markerType: 'circle',
211
+ lineThickness: 2,
212
+ dataPoints: this.setDataPoints(this.failedJobsCountHistory),
213
+ },
165
214
  ]
166
- }]
167
- });
215
+ });
168
216
 
169
- var queuedJobsChart = new CanvasJS.Chart('queued_jobs_container', {
170
- title: {
171
- text: 'Queued Jobs',
172
- fontSize: 24,
173
- },
174
- axisX: {
175
- reversed: true,
176
- gridColor: 'Silver',
177
- tickColor: 'silver',
178
- animationEnabled: true,
179
- title: 'Time ago (s)',
180
- // minimum: 0,
181
- maximum: 60
182
- },
183
- toolTip: {
184
- shared: true
185
- },
186
- theme: "theme2",
187
- axisY: {
188
- gridColor: "Silver",
189
- tickColor: "silver",
190
- title: 'Jobs'
191
- },
192
- data: [{
193
- type: "line",
194
- showInLegend: true,
195
- lineThickness: 2,
196
- name: "Queued Jobs",
197
- markerType: "circle",
198
- color: "#F08080",
199
- dataPoints: [
200
- { x: '0', y: queuedJobsCountHistory[0] },
201
- { x: '5', y: queuedJobsCountHistory[1] },
202
- { x: '10', y: queuedJobsCountHistory[2] },
203
- { x: '15', y: queuedJobsCountHistory[3] },
204
- { x: '20', y: queuedJobsCountHistory[4] },
205
- { x: '25', y: queuedJobsCountHistory[5] },
206
- { x: '30', y: queuedJobsCountHistory[6] },
207
- { x: '35', y: queuedJobsCountHistory[7] },
208
- { x: '40', y: queuedJobsCountHistory[8] },
209
- { x: '45', y: queuedJobsCountHistory[9] },
210
- { x: '50', y: queuedJobsCountHistory[10] },
211
- { x: '55', y: queuedJobsCountHistory[11] },
212
- { x: '60', y: queuedJobsCountHistory[12] },
213
- ]
217
+ var totalMemoryChart = new CanvasJS.Chart('total_memory_container', {
218
+ title: {
219
+ text: 'Memory Usage',
220
+ fontFamily: 'Arial',
221
+ fontSize: 24,
214
222
  },
215
- ],
216
- });
217
-
218
- var failedJobsChart = new CanvasJS.Chart('failed_jobs_container', {
219
- title: {
220
- text: 'Failed Jobs',
221
- fontSize: 24,
222
- },
223
- axisX: {
224
- reversed: true,
225
- gridColor: 'Silver',
226
- tickColor: 'silver',
227
- animationEnabled: true,
228
- title: 'Time ago (s)',
229
- // minimum: 0,
230
- maximum: 60
231
- },
232
- toolTip: {
233
- shared: true
234
- },
235
- theme: "theme2",
236
- axisY: {
237
- gridColor: "Silver",
238
- tickColor: "silver",
239
- title: 'Jobs'
240
- },
241
- data: [{
223
+ axisX: {
224
+ reversed: true,
225
+ gridColor: 'Silver',
226
+ tickColor: 'silver',
227
+ animationEnabled: true,
228
+ title: 'Time ago (s)',
229
+ // minimum: 0,
230
+ maximum: 60
231
+ },
232
+ toolTip: {
233
+ shared: true
234
+ },
235
+ theme: "theme2",
236
+ axisY: {
237
+ gridColor: "Silver",
238
+ tickColor: "silver",
239
+ title: 'Memory (mb)'
240
+ },
241
+ data: [{
242
242
  type: "line",
243
243
  showInLegend: true,
244
- name: "Failed Jobs",
244
+ name: "Memory usage",
245
245
  color: "#20B2AA",
246
246
  markerType: 'circle',
247
247
  lineThickness: 2,
248
- dataPoints: [
249
- { x: '0', y: failedJobsCountHistory[0] },
250
- { x: '5', y: failedJobsCountHistory[1] },
251
- { x: '10', y: failedJobsCountHistory[2] },
252
- { x: '15', y: failedJobsCountHistory[3] },
253
- { x: '20', y: failedJobsCountHistory[4] },
254
- { x: '25', y: failedJobsCountHistory[5] },
255
- { x: '30', y: failedJobsCountHistory[6] },
256
- { x: '35', y: failedJobsCountHistory[7] },
257
- { x: '40', y: failedJobsCountHistory[8] },
258
- { x: '45', y: failedJobsCountHistory[9] },
259
- { x: '50', y: failedJobsCountHistory[10] },
260
- { x: '55', y: failedJobsCountHistory[11] },
261
- { x: '60', y: failedJobsCountHistory[12] },
262
- ]
263
- },
264
- ]
265
- });
248
+ dataPoints: this.setDataPoints(this.totalMemoryHistory),
249
+ }],
250
+ });
251
+
252
+ queuedJobsChart.render();
253
+ failedJobsChart.render();
254
+ processedJobsChart.render();
255
+ totalMemoryChart.render();
256
+ },
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
+ ];
273
+
274
+ return data;
275
+ },
276
+ setActiveTab: function() {
277
+ this.tab = $(location).attr('href').split('/').pop();
278
+ var $active = $('a[href=' + this.tab + ']');
279
+
280
+ $active.css('background', '#a2a2a2');
281
+ $active.css('color', '#fff');
282
+ },
283
+ pollData: function(tab) {
284
+ if (tab === 'overview') {
285
+ this.getOverviewData();
266
286
 
267
- queuedJobsChart.render();
268
- failedJobsChart.render();
269
- processedJobsChart.render();
287
+ setInterval(function() {
288
+ this.getOverviewData();
289
+ }.bind(this), 5000);
290
+ }
291
+
292
+ if (tab === 'queues') {
293
+ setInterval(function() {
294
+ this.getQueueData();
295
+ }.bind(this), 5000);
296
+ }
297
+
298
+ if (tab === 'details') {
299
+ setInterval(function() {
300
+ this.getDetailData();
301
+ }.bind(this), 5000);
302
+ }
303
+ },
304
+ bindEvents: function() {
305
+ $('#memory_usage').on('click', function(e) {
306
+ $('.nested th').toggle();
307
+ });
308
+ },
309
+ init: function() {
310
+ this.setActiveTab();
311
+ this.bindEvents();
312
+ this.pollData(this.tab);
313
+ }
270
314
  }
315
+
316
+ $(document).ready(App.init.bind(App));