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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dc2f98f3447708cde0fa772761604dd850335719
4
- data.tar.gz: 30a2b6653e1bd686d6c02f97dae56cd2853e0518
3
+ metadata.gz: 356fda8449bf808280461964fd361d5960d4098f
4
+ data.tar.gz: 2bc6419214d9b6498bc132ff8cb5db842b0ebb43
5
5
  SHA512:
6
- metadata.gz: edd9e384ff237692df629d3e91fe6a97fa7c0f879f8ffa94c19f279d08106f21da28abce50964ea3fd9718fcc2708c263f1179c8fd6b121fa3949c0213cfa170
7
- data.tar.gz: 36a454d8a2981a1c315b12c2f3d92d99b5f4fef5569583286a8658236d161eb975b3d2aeeaffe24665f38c656beca6ad13b7dbef5173963b5d832d2f4cf9e644
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
- worker = WorkerArmy::Worker.new
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
- worker.job = clazz.new
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.3.2
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
@@ -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(config)
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 config and config['client_retry_count']
55
- return config['client_retry_count'].to_i
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
@@ -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 = Queue.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 = Queue.config unless $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 failed_jobs
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
- workers
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 finished_jobs
158
+ def finished_jobs_count
132
159
  Queue.redis_instance.llen 'jobs'
133
160
  end
134
161
 
@@ -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.finished_jobs
16
- failed_jobs = queue.failed_jobs
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, workers: workers,
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
@@ -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, :config
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
- begin
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 ready! Waiting for jobs: #{@job.class.name}")
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(config = nil)
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 config and config['worker_retry_count']
82
- return config['worker_retry_count'].to_i
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.3.2 ruby lib
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.3.2"
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-28"
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.3.2
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-28 00:00:00.000000000 Z
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