worker-army 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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