worker-army 0.3.2 → 0.4.0
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.
- checksums.yaml +4 -4
- data/Rakefile +2 -6
- data/VERSION +1 -1
- data/lib/worker-army.rb +1 -0
- data/lib/worker_army/base.rb +33 -0
- data/lib/worker_army/client.rb +6 -16
- data/lib/worker_army/queue.rb +56 -29
- data/lib/worker_army/web.rb +26 -4
- data/lib/worker_army/worker.rb +14 -14
- data/worker-army.gemspec +4 -3
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 356fda8449bf808280461964fd361d5960d4098f
|
|
4
|
+
data.tar.gz: 2bc6419214d9b6498bc132ff8cb5db842b0ebb43
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3b62516a6387cf9e5ab8350bf823f63812fa9b90197cb746bc26e98a2bab4d3ba1a38b4e282d83c3f55480f1b01db7d15ded35cbbbe94869102fd5b4c889bdb4
|
|
7
|
+
data.tar.gz: 0104f1aa27d28a0f3b2d18455dff4dde4f23c4bc23295ab989a06d540cbb89b98489e2791a463b8c769fcb96c64a4a0f951fd5c930d3628e6a116018060f2405
|
data/Rakefile
CHANGED
|
@@ -43,17 +43,13 @@ end
|
|
|
43
43
|
|
|
44
44
|
require File.dirname(__FILE__) + '/lib/worker-army'
|
|
45
45
|
task 'start_example_worker' do
|
|
46
|
-
|
|
47
|
-
worker.job = ExampleJob.new
|
|
48
|
-
worker.process_queue
|
|
46
|
+
WorkerArmy::Worker.new(ExampleJob.new).process_queue
|
|
49
47
|
end
|
|
50
48
|
|
|
51
49
|
desc "Start a worker-army worker to execute a job class"
|
|
52
50
|
task :start_worker, :job_class do |t, args|
|
|
53
51
|
if args[:job_class]
|
|
54
|
-
worker = WorkerArmy::Worker.new
|
|
55
52
|
clazz = Object.const_get(args[:job_class].to_s)
|
|
56
|
-
|
|
57
|
-
worker.process_queue
|
|
53
|
+
WorkerArmy::Worker.new(clazz.new).process_queue
|
|
58
54
|
end
|
|
59
55
|
end
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.4.0
|
data/lib/worker-army.rb
CHANGED
|
@@ -2,6 +2,7 @@ require "redis"
|
|
|
2
2
|
require "logger"
|
|
3
3
|
|
|
4
4
|
require File.dirname(__FILE__) + '/worker_army/log'
|
|
5
|
+
require File.dirname(__FILE__) + '/worker_army/base'
|
|
5
6
|
require File.dirname(__FILE__) + '/worker_army/queue'
|
|
6
7
|
require File.dirname(__FILE__) + '/worker_army/worker'
|
|
7
8
|
require File.dirname(__FILE__) + '/worker_army/client'
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module WorkerArmy
|
|
2
|
+
class Base
|
|
3
|
+
attr_accessor :config
|
|
4
|
+
|
|
5
|
+
class << self
|
|
6
|
+
def config
|
|
7
|
+
if ENV['worker_army_redis_host'] and ENV['worker_army_redis_port']
|
|
8
|
+
config = { 'redis_host' => ENV['worker_army_redis_host'], 'redis_port' => ENV['worker_army_redis_port'] }
|
|
9
|
+
if ENV['worker_army_redis_auth']
|
|
10
|
+
config['redis_auth'] = ENV['worker_army_redis_auth']
|
|
11
|
+
end
|
|
12
|
+
if ENV['worker_army_worker_retry_count']
|
|
13
|
+
config['worker_retry_count'] = ENV['worker_army_worker_retry_count'].to_i
|
|
14
|
+
end
|
|
15
|
+
if ENV['worker_army_client_retry_count']
|
|
16
|
+
config['client_retry_count'] = ENV['worker_army_client_retry_count'].to_i
|
|
17
|
+
end
|
|
18
|
+
if ENV['worker_army_endpoint']
|
|
19
|
+
config['endpoint'] = ENV['worker_army_endpoint']
|
|
20
|
+
end
|
|
21
|
+
else
|
|
22
|
+
begin
|
|
23
|
+
# puts "Using config in your home directory"
|
|
24
|
+
config = YAML.load(File.read("#{ENV['HOME']}/.worker_army.yml"))
|
|
25
|
+
rescue Errno::ENOENT
|
|
26
|
+
raise "worker-army configuration expected in ~/.worker_army.yml or provide env vars..."
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
config
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
data/lib/worker_army/client.rb
CHANGED
|
@@ -1,26 +1,16 @@
|
|
|
1
1
|
require "rest-client"
|
|
2
2
|
require "json"
|
|
3
3
|
require "multi_json"
|
|
4
|
+
require File.dirname(__FILE__) + '/base'
|
|
4
5
|
|
|
5
6
|
module WorkerArmy
|
|
6
|
-
class Client
|
|
7
|
+
class Client < Base
|
|
7
8
|
class << self
|
|
8
9
|
def push_job(job_class, data = {}, callback_url = nil, queue_prefix = 'queue', retry_count = 0)
|
|
9
10
|
raise "No data" unless data
|
|
10
11
|
raise "No job class provided" unless job_class
|
|
11
|
-
|
|
12
|
-
if ENV['worker_army_endpoint']
|
|
13
|
-
# puts "Using environment variables for config..."
|
|
14
|
-
@config = { endpoint: ENV['worker_army_endpoint'] }
|
|
15
|
-
else
|
|
16
|
-
begin
|
|
17
|
-
# puts "Using config in your home directory"
|
|
18
|
-
@config = YAML.load(File.read("#{ENV['HOME']}/.worker_army.yml"))
|
|
19
|
-
rescue Errno::ENOENT
|
|
20
|
-
raise "worker_army.yml expected in ~/.worker_army.yml"
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
12
|
|
|
13
|
+
@config = self.config
|
|
24
14
|
worker_army_base_url = @config['endpoint']
|
|
25
15
|
callback_url = "#{worker_army_base_url}/generic_callback" unless callback_url
|
|
26
16
|
response = nil
|
|
@@ -48,11 +38,11 @@ module WorkerArmy
|
|
|
48
38
|
end
|
|
49
39
|
end
|
|
50
40
|
|
|
51
|
-
def client_retry_count(
|
|
41
|
+
def client_retry_count(conf = nil)
|
|
52
42
|
if ENV['worker_army_client_retry_count']
|
|
53
43
|
return ENV['worker_army_client_retry_count'].to_i
|
|
54
|
-
elsif
|
|
55
|
-
return
|
|
44
|
+
elsif conf and conf['client_retry_count']
|
|
45
|
+
return conf['client_retry_count'].to_i
|
|
56
46
|
else
|
|
57
47
|
return 10
|
|
58
48
|
end
|
data/lib/worker_army/queue.rb
CHANGED
|
@@ -4,38 +4,19 @@ require "json"
|
|
|
4
4
|
require "multi_json"
|
|
5
5
|
require "yaml"
|
|
6
6
|
require 'securerandom'
|
|
7
|
+
require File.dirname(__FILE__) + '/base'
|
|
7
8
|
|
|
8
9
|
module WorkerArmy
|
|
9
|
-
class Queue
|
|
10
|
-
attr_accessor :config
|
|
11
|
-
|
|
10
|
+
class Queue < Base
|
|
12
11
|
def initialize
|
|
13
|
-
@config =
|
|
14
|
-
# puts "Config: #{@config}"
|
|
12
|
+
@config = self.config
|
|
15
13
|
Queue.redis_instance
|
|
16
14
|
@log = WorkerArmy::Log.new.log
|
|
17
15
|
end
|
|
18
16
|
|
|
19
17
|
class << self
|
|
20
|
-
def config
|
|
21
|
-
if ENV['worker_army_redis_host'] and ENV['worker_army_redis_port']
|
|
22
|
-
config = { 'redis_host' => ENV['worker_army_redis_host'], 'redis_port' => ENV['worker_army_redis_port'] }
|
|
23
|
-
if ENV['worker_army_redis_auth']
|
|
24
|
-
config['redis_auth'] = ENV['worker_army_redis_auth']
|
|
25
|
-
end
|
|
26
|
-
else
|
|
27
|
-
begin
|
|
28
|
-
# puts "Using config in your home directory"
|
|
29
|
-
config = YAML.load(File.read("#{ENV['HOME']}/.worker_army.yml"))
|
|
30
|
-
rescue Errno::ENOENT
|
|
31
|
-
raise "worker_army.yml expected in ~/.worker_army.yml"
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
config
|
|
35
|
-
end
|
|
36
|
-
|
|
37
18
|
def redis_instance
|
|
38
|
-
$config =
|
|
19
|
+
$config = self.config unless $config
|
|
39
20
|
unless $redis
|
|
40
21
|
$redis = Redis.new(host: $config['redis_host'], port: $config['redis_port'])
|
|
41
22
|
end
|
|
@@ -76,28 +57,73 @@ module WorkerArmy
|
|
|
76
57
|
if data
|
|
77
58
|
job_id = data['job_id']
|
|
78
59
|
callback_url = data['callback_url']
|
|
79
|
-
Queue.redis_instance["job_#{job_id}"] = data
|
|
60
|
+
Queue.redis_instance["job_#{job_id}"] = data.to_json
|
|
80
61
|
Queue.redis_instance.lpush 'jobs', job_id
|
|
81
62
|
if callback_url
|
|
82
63
|
data.delete("callback_url")
|
|
83
64
|
begin
|
|
84
65
|
response = RestClient.post callback_url.split("?callback_url=").last,
|
|
85
66
|
data.to_json, :content_type => :json, :accept => :json
|
|
67
|
+
if response.code == 404 or response.code == 500
|
|
68
|
+
@log.error("Response from callback url: #{response.code}")
|
|
69
|
+
add_failed_callback_job(job_id)
|
|
70
|
+
end
|
|
86
71
|
rescue => e
|
|
87
72
|
@log.error(e)
|
|
73
|
+
add_failed_callback_job(job_id)
|
|
88
74
|
end
|
|
89
75
|
end
|
|
90
76
|
end
|
|
91
77
|
end
|
|
92
78
|
|
|
79
|
+
def add_current_job(job_id)
|
|
80
|
+
Queue.redis_instance.sadd 'current_jobs', job_id
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def remove_current_job(job_id)
|
|
84
|
+
Queue.redis_instance.srem 'current_jobs', job_id
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def current_jobs_count
|
|
88
|
+
Queue.redis_instance.scard 'current_jobs'
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def current_jobs
|
|
92
|
+
Queue.redis_instance.smembers 'current_jobs'
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def clear_current_jobs
|
|
96
|
+
Queue.redis_instance.del 'current_jobs'
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def job_data(job_id)
|
|
100
|
+
Queue.redis_instance["job_#{job_id}"]
|
|
101
|
+
end
|
|
102
|
+
|
|
93
103
|
def add_failed_job(job_id)
|
|
94
104
|
Queue.redis_instance.lpush 'failed_jobs', job_id
|
|
95
105
|
end
|
|
96
|
-
|
|
97
|
-
def
|
|
106
|
+
|
|
107
|
+
def add_failed_callback_job(job_id)
|
|
108
|
+
Queue.redis_instance.lpush 'failed_callback_jobs', job_id
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def failed_jobs_count
|
|
98
112
|
Queue.redis_instance.llen 'failed_jobs'
|
|
99
113
|
end
|
|
100
114
|
|
|
115
|
+
def failed_jobs
|
|
116
|
+
Queue.redis_instance.lrange 'failed_jobs', 0, failed_jobs_count
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def failed_callback_jobs_count
|
|
120
|
+
Queue.redis_instance.llen 'failed_callback_jobs'
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def failed_callback_jobs
|
|
124
|
+
Queue.redis_instance.lrange 'failed_callback_jobs', 0, failed_callback_jobs_count
|
|
125
|
+
end
|
|
126
|
+
|
|
101
127
|
def ping(data)
|
|
102
128
|
Queue.redis_instance.lpush 'workers', data.to_json
|
|
103
129
|
Queue.redis_instance.set 'last_ping', data[:timestamp].to_i
|
|
@@ -121,14 +147,15 @@ module WorkerArmy
|
|
|
121
147
|
end
|
|
122
148
|
end
|
|
123
149
|
end
|
|
124
|
-
|
|
150
|
+
now = Time.now.utc.to_i
|
|
151
|
+
workers.select {|h| h if now - h['timestamp'].to_i < 3600}
|
|
125
152
|
end
|
|
126
|
-
|
|
153
|
+
|
|
127
154
|
def get_known_queues
|
|
128
155
|
Queue.redis_instance.smembers 'known_queues'
|
|
129
156
|
end
|
|
130
157
|
|
|
131
|
-
def
|
|
158
|
+
def finished_jobs_count
|
|
132
159
|
Queue.redis_instance.llen 'jobs'
|
|
133
160
|
end
|
|
134
161
|
|
data/lib/worker_army/web.rb
CHANGED
|
@@ -7,16 +7,23 @@ require File.dirname(__FILE__) + '/queue'
|
|
|
7
7
|
|
|
8
8
|
queue = WorkerArmy::Queue.new
|
|
9
9
|
|
|
10
|
+
before do
|
|
11
|
+
content_type 'application/json', :charset => 'utf-8'
|
|
12
|
+
end
|
|
13
|
+
|
|
10
14
|
get '/' do
|
|
11
15
|
job_count = queue.get_job_count || 0
|
|
12
16
|
workers = queue.get_known_workers
|
|
13
17
|
last_ping = queue.last_ping || 0
|
|
14
18
|
queues = queue.get_known_queues
|
|
15
|
-
finished_jobs = queue.
|
|
16
|
-
|
|
19
|
+
finished_jobs = queue.finished_jobs_count
|
|
20
|
+
failed_callback_jobs = queue.failed_callback_jobs_count
|
|
21
|
+
failed_jobs = queue.failed_jobs_count
|
|
22
|
+
current_jobs = queue.current_jobs
|
|
17
23
|
data = { job_count: job_count, finished_jobs: finished_jobs,
|
|
18
|
-
failed_jobs: failed_jobs,
|
|
19
|
-
last_worker_ping: last_ping.to_i, queues: queues
|
|
24
|
+
failed_jobs: failed_jobs, failed_callback_jobs: failed_callback_jobs,
|
|
25
|
+
workers: workers, last_worker_ping: last_ping.to_i, queues: queues,
|
|
26
|
+
current_jobs: current_jobs
|
|
20
27
|
}
|
|
21
28
|
json data
|
|
22
29
|
end
|
|
@@ -27,6 +34,11 @@ post '/jobs' do
|
|
|
27
34
|
json queue_job
|
|
28
35
|
end
|
|
29
36
|
|
|
37
|
+
get '/jobs/:job_id' do
|
|
38
|
+
data = queue.job_data(params[:job_id])
|
|
39
|
+
json JSON.parse(data)
|
|
40
|
+
end
|
|
41
|
+
|
|
30
42
|
post '/callback' do
|
|
31
43
|
data = JSON.parse(request.body.read)
|
|
32
44
|
queue.save_result(data) if data
|
|
@@ -38,3 +50,13 @@ post '/generic_callback' do
|
|
|
38
50
|
status = { :status => 'ok' }
|
|
39
51
|
json status
|
|
40
52
|
end
|
|
53
|
+
|
|
54
|
+
get '/failed_jobs' do
|
|
55
|
+
failed_jobs = queue.failed_jobs
|
|
56
|
+
json failed_jobs
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
get '/failed_callback_jobs' do
|
|
60
|
+
failed_callback_jobs = queue.failed_callback_jobs
|
|
61
|
+
json failed_callback_jobs
|
|
62
|
+
end
|
data/lib/worker_army/worker.rb
CHANGED
|
@@ -2,22 +2,19 @@ require "rest-client"
|
|
|
2
2
|
require "json"
|
|
3
3
|
require "multi_json"
|
|
4
4
|
require 'socket'
|
|
5
|
+
require File.dirname(__FILE__) + '/base'
|
|
5
6
|
|
|
6
7
|
module WorkerArmy
|
|
7
|
-
class Worker
|
|
8
|
-
attr_accessor :queue, :job, :worker_name, :processed, :failed
|
|
9
|
-
def initialize(worker_name = nil)
|
|
8
|
+
class Worker < Base
|
|
9
|
+
attr_accessor :queue, :job, :worker_name, :processed, :failed
|
|
10
|
+
def initialize(job, worker_name = nil)
|
|
10
11
|
@queue = WorkerArmy::Queue.new
|
|
12
|
+
@job = job
|
|
11
13
|
@worker_name = worker_name
|
|
12
14
|
@host_name = Socket.gethostname
|
|
13
15
|
@processed = 0
|
|
14
16
|
@failed = 0
|
|
15
|
-
|
|
16
|
-
# puts "Using config in your home directory"
|
|
17
|
-
@config = YAML.load(File.read("#{ENV['HOME']}/.worker_army.yml"))
|
|
18
|
-
rescue Errno::ENOENT
|
|
19
|
-
# ignore
|
|
20
|
-
end
|
|
17
|
+
@config = self.config
|
|
21
18
|
@log = WorkerArmy::Log.new.log
|
|
22
19
|
end
|
|
23
20
|
|
|
@@ -26,8 +23,8 @@ module WorkerArmy
|
|
|
26
23
|
@job.log = @log if @job.respond_to?(:log)
|
|
27
24
|
@queue.ping(worker_pid: Process.pid, job_name: @job.class.name, host_name: @host_name,
|
|
28
25
|
timestamp: Time.now.utc.to_i)
|
|
29
|
-
@log.info("Worker
|
|
30
|
-
@log.info("Processed: #{@processed} - Failed: #{@failed}")
|
|
26
|
+
@log.info("Worker #{@host_name}-#{Process.pid} => Queue: queue_#{@job.class.name}")
|
|
27
|
+
@log.info("Worker #{@host_name}-#{Process.pid} => Processed: #{@processed} - Failed: #{@failed}")
|
|
31
28
|
list, element = @queue.pop(@job.class.name)
|
|
32
29
|
if list and element
|
|
33
30
|
execute_job(list, element, 0)
|
|
@@ -44,6 +41,7 @@ module WorkerArmy
|
|
|
44
41
|
job_id = data['job_id']
|
|
45
42
|
callback_url = data['callback_url']
|
|
46
43
|
if @job and @job.class.name == data['job_class']
|
|
44
|
+
@queue.add_current_job(job_id)
|
|
47
45
|
response_data = @job.perform(data)
|
|
48
46
|
response_data = {} unless response_data
|
|
49
47
|
response_data.merge!(job_id: job_id, callback_url: callback_url,
|
|
@@ -53,8 +51,10 @@ module WorkerArmy
|
|
|
53
51
|
response_data.merge!(worker_name: @worker_name)
|
|
54
52
|
end
|
|
55
53
|
end
|
|
54
|
+
@queue.remove_current_job(job_id)
|
|
56
55
|
response_data
|
|
57
56
|
rescue => e
|
|
57
|
+
@queue.remove_current_job(job_id)
|
|
58
58
|
@log.error(e)
|
|
59
59
|
retry_count += 1
|
|
60
60
|
if retry_count < worker_retry_count(@config)
|
|
@@ -75,11 +75,11 @@ module WorkerArmy
|
|
|
75
75
|
self.process_queue
|
|
76
76
|
end
|
|
77
77
|
|
|
78
|
-
def worker_retry_count(
|
|
78
|
+
def worker_retry_count(conf = nil)
|
|
79
79
|
if ENV['worker_army_worker_retry_count']
|
|
80
80
|
return ENV['worker_army_worker_retry_count'].to_i
|
|
81
|
-
elsif
|
|
82
|
-
return
|
|
81
|
+
elsif conf and conf['worker_retry_count']
|
|
82
|
+
return conf['worker_retry_count'].to_i
|
|
83
83
|
else
|
|
84
84
|
return 10
|
|
85
85
|
end
|
data/worker-army.gemspec
CHANGED
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
|
4
4
|
# -*- encoding: utf-8 -*-
|
|
5
|
-
# stub: worker-army 0.
|
|
5
|
+
# stub: worker-army 0.4.0 ruby lib
|
|
6
6
|
|
|
7
7
|
Gem::Specification.new do |s|
|
|
8
8
|
s.name = "worker-army"
|
|
9
|
-
s.version = "0.
|
|
9
|
+
s.version = "0.4.0"
|
|
10
10
|
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
12
12
|
s.require_paths = ["lib"]
|
|
13
13
|
s.authors = ["Oliver Kiessler"]
|
|
14
|
-
s.date = "2014-05-
|
|
14
|
+
s.date = "2014-05-29"
|
|
15
15
|
s.description = "Simple redis based worker queue with a HTTP/Rest interface"
|
|
16
16
|
s.email = "kiessler@inceedo.com"
|
|
17
17
|
s.executables = ["worker_army"]
|
|
@@ -32,6 +32,7 @@ Gem::Specification.new do |s|
|
|
|
32
32
|
"bin/worker_army",
|
|
33
33
|
"config.ru",
|
|
34
34
|
"lib/worker-army.rb",
|
|
35
|
+
"lib/worker_army/base.rb",
|
|
35
36
|
"lib/worker_army/client.rb",
|
|
36
37
|
"lib/worker_army/example_job.rb",
|
|
37
38
|
"lib/worker_army/log.rb",
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: worker-army
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Oliver Kiessler
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2014-05-
|
|
11
|
+
date: 2014-05-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: redis
|
|
@@ -171,6 +171,7 @@ files:
|
|
|
171
171
|
- bin/worker_army
|
|
172
172
|
- config.ru
|
|
173
173
|
- lib/worker-army.rb
|
|
174
|
+
- lib/worker_army/base.rb
|
|
174
175
|
- lib/worker_army/client.rb
|
|
175
176
|
- lib/worker_army/example_job.rb
|
|
176
177
|
- lib/worker_army/log.rb
|