disquo 0.3.0 → 0.3.1

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: 1f9ffa4b76dc43b762c79ff560a981b71d8e6bfb
4
- data.tar.gz: 4c320fe08f60dd1d9fc18a190e65ef73d06cff64
3
+ metadata.gz: e4a5a02702349eb8b6c55ccda7678d0ec5374f9d
4
+ data.tar.gz: 2793c75864c561a6d96833c7a171c687b0bda854
5
5
  SHA512:
6
- metadata.gz: 143053e6aa72ef607a876baa1059457e1db32a75e300448529feb3363ec991919b5c70bae3c147b6ac0b9a3095af862fb4c9dd8962bca0b2702943d650c48984
7
- data.tar.gz: ef07e3fe2b6c36d4a759d9564475881b43a9bb9319016440662e49b3e3de5aed64d912c5995a56b08abe4ddeb04d62f2cca09bf3ec3a3e9874e528e36297d7c1
6
+ metadata.gz: bd458037bec4658dd490234ca46ab75f82f3f74e40deb1e6a65d95eea6e3ddf49d3a7f0770885389830be92fed26124e3a66422fad584382fc21ec33ee9f0618
7
+ data.tar.gz: e0575ada72338c810ee9186104f75b1478d8518f7a91bd5e5ed2218282c1d5c52ea99988b69c8c0550197cbf04d5e2d89919d1a6a7175d21e261f5733572b707
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ pkg/
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- disquo (0.3.0)
4
+ disquo (0.3.1)
5
5
  concurrent-ruby
6
6
  connection_pool
7
7
  disque
data/disquo.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "disquo"
5
- s.version = "0.3.0"
5
+ s.version = "0.3.1"
6
6
  s.platform = Gem::Platform::RUBY
7
7
 
8
8
  s.licenses = ["Apache-2.0"]
data/lib/disquo/worker.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'disquo'
2
- require 'concurrent'
3
2
  require 'concurrent/executor/fixed_thread_pool'
3
+ require 'concurrent/atomic/atomic_fixnum'
4
4
 
5
5
  class Disquo::Worker
6
6
  attr_reader :disque, :queues, :wait_time, :wait_count
@@ -10,19 +10,18 @@ class Disquo::Worker
10
10
  # @param [Hash] options
11
11
  # @option [Array<String>] :queues queues to watch. Default: ["default"]
12
12
  # @option [Integer] :concurrency the number of concurrent threads. Default: 10
13
- # @option [Numeric] :wait_time maximum time (in seconds) to block for when retrieving next batch. Default: 1s
14
- # @option [Integer] :wait_count the minimum number of jobs to wait for when retrieving next batch. Default: 100
15
- def initialize(disque, queues: [Disquo::DEFAULT_QUEUE], concurrency: 10, wait_time: 1, wait_count: 100)
13
+ # @option [Numeric] :wait_time maximum time (in seconds) to wait for jobs when retrieving next batch. Default: 1s
14
+ def initialize(disque, queues: [Disquo::DEFAULT_QUEUE], concurrency: 10, wait_time: 1)
16
15
  @disque = disque
17
16
  @queues = Array(queues)
18
17
  @threads = Concurrent::FixedThreadPool.new(concurrency)
18
+ @busy = Concurrent::AtomicFixnum.new
19
19
  @wait_time = wait_time
20
- @wait_count = wait_count
21
20
  end
22
21
 
23
22
  # Run starts the worker
24
23
  def run
25
- Disquo.logger.info "Starting worker - queues: #{queues.inspect}, concurrency: #{@threads.max_length}"
24
+ Disquo.logger.info "Worker starting - queues: #{queues.inspect}, concurrency: #{@threads.max_length}"
26
25
 
27
26
  begin
28
27
  run_cycle
@@ -30,14 +29,14 @@ class Disquo::Worker
30
29
  handle_exception(e)
31
30
  end until @stopped
32
31
 
32
+ Disquo.logger.info "Worker shutting down"
33
33
  @threads.shutdown
34
34
  end
35
35
 
36
36
  # Blocks until worker is stopped
37
37
  def wait(timeout = nil)
38
- Disquo.logger.info "Waiting for worker shutdown"
39
38
  @threads.wait_for_termination(timeout)
40
- Disquo.logger.info "Shutdown complete"
39
+ Disquo.logger.info "Worker shutdown complete"
41
40
  end
42
41
 
43
42
  # Stops the worker
@@ -50,57 +49,69 @@ class Disquo::Worker
50
49
  private
51
50
 
52
51
  def run_cycle
53
- jobs = next_batch
54
-
52
+ jobs = Array(next_batch)
55
53
  until @stopped || jobs.empty?
56
54
  job = jobs.shift
57
- perform(*job)
55
+ schedule(*job)
58
56
  end
59
57
  ensure
60
58
  requeue(jobs) unless jobs.nil? || jobs.empty?
61
59
  end
62
60
 
63
61
  def next_batch
62
+ count = @threads.max_length - @busy.value
63
+ if count < 1
64
+ sleep(wait_time.fdiv(2))
65
+ return
66
+ end
67
+
64
68
  jobs = disque.with do |cn|
65
- cn.fetch from: queues, timeout: (wait_time*1000).to_i, count: wait_count
69
+ cn.fetch from: queues, timeout: (wait_time*1000).to_i, count: count
66
70
  end
71
+
67
72
  @is_down = nil
68
- Array(jobs)
69
- rescue => e
70
- if !@is_down
71
- @is_down = true
72
- handle_exception(e, message: 'Error retrieving jobs:')
73
- end
74
- sleep(1)
75
- []
73
+ jobs
74
+ rescue Errno::ECONNREFUSED => e
75
+ handle_disque_exception e, message: "Failed to retrieve jobs:", notrace: true
76
+ nil
76
77
  end
77
78
 
78
- def perform(queue, job_id, payload)
79
+ def schedule(queue, job_id, payload)
80
+ @busy.increment
79
81
  @threads.post do
80
- thread_id = Thread.current.object_id.to_s(36)
81
- Disquo.logger.info { "Process #{payload} - thread: #{thread_id}, job: #{job_id}" }
82
-
83
82
  begin
84
- class_name, args = Disquo.load_job(payload)
85
-
86
- job = Object.const_get(class_name).new
87
- job.disque = disque
88
- job.queue = queue
89
- job.job_id = job_id
90
- job.perform(*args)
91
- rescue => e
92
- handle_exception e, message: "Error processing #{payload} - thread: #{thread_id}, job: #{job_id}:"
93
-
94
- disque.with {|cn| cn.call :nack, job_id }
95
- return
83
+ perform(queue, job_id, payload)
84
+ ensure
85
+ @busy.decrement
96
86
  end
87
+ end
88
+ end
97
89
 
98
- begin
99
- disque.with {|cn| cn.call :ackjob, job_id }
100
- rescue => e
101
- handle_exception e, message: "Error ACKing #{payload} - thread: #{thread_id}, job: #{job_id}:"
102
- return
103
- end
90
+ def perform(queue, job_id, payload)
91
+ thread_id = Thread.current.object_id.to_s(36)
92
+ Disquo.logger.info { "Process #{payload} - thread: #{thread_id}, job: #{job_id}" }
93
+
94
+ begin
95
+ class_name, args = Disquo.load_job(payload)
96
+
97
+ job = Object.const_get(class_name).new
98
+ job.disque = disque
99
+ job.queue = queue
100
+ job.job_id = job_id
101
+ job.perform(*args)
102
+ rescue => e
103
+ handle_exception e, message: "Error processing #{payload} - thread: #{thread_id}, job: #{job_id}:"
104
+
105
+ disque.with {|cn| cn.call :nack, job_id }
106
+ return
107
+ end
108
+
109
+ begin
110
+ disque.with {|cn| cn.call :ackjob, job_id }
111
+ @is_down = nil
112
+ rescue Errno::ECONNREFUSED => e
113
+ handle_disque_exception e, message: "Failed to ACK job #{job_id}:", notrace: true
114
+ retry unless @stopped
104
115
  end
105
116
  end
106
117
 
@@ -109,11 +120,19 @@ class Disquo::Worker
109
120
  disque.with {|cn| cn.call :enqueue, *ids }
110
121
  end
111
122
 
123
+ def handle_disque_exception(e, opts = {})
124
+ if !@is_down
125
+ @is_down = true
126
+ handle_exception(e, opts)
127
+ end
128
+ sleep(1)
129
+ end
130
+
112
131
  def handle_exception(e, opts = {})
113
132
  lines = [
114
133
  opts[:message],
115
134
  "#{e.class.name}: #{e.message}",
116
- e.backtrace
135
+ (opts[:notrace] ? nil : e.backtrace),
117
136
  ].compact.flatten
118
137
 
119
138
  Disquo.logger.error lines.join("\n")
@@ -3,11 +3,12 @@ require 'spec_helper'
3
3
  RSpec.describe Disquo::Worker do
4
4
 
5
5
  subject do
6
- described_class.new Disquo.connect, wait_time: 0.1, wait_count: 11, queues: Disquo::TEST::QUEUE
6
+ described_class.new Disquo.connect, wait_time: 0.1, queues: Disquo::TEST::QUEUE
7
7
  end
8
8
 
9
9
  it "should run/process/shutdown" do
10
10
  runner = Thread.new { subject.run }
11
+ runner.abort_on_exception = true
11
12
 
12
13
  # seed 200 jobs
13
14
  200.times {|n| TestJob.enqueue(n) }
@@ -33,12 +34,13 @@ RSpec.describe Disquo::Worker do
33
34
  queue: "__disquo_test__",
34
35
  )
35
36
  expect(Disquo::TEST::PERFORMED.last[:job_id]).to match(/^D\w+/)
37
+ expect(Disquo::TEST::PERFORMED.map {|e| e[:args].first }).to match_array(0..199)
36
38
  end
37
39
 
38
40
  def wait_for
39
41
  20.times do
40
42
  break if yield
41
- sleep(0.01)
43
+ sleep(0.1)
42
44
  end
43
45
  end
44
46
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: disquo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dimitrij Denissenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-23 00:00:00.000000000 Z
11
+ date: 2017-11-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: disque
@@ -87,6 +87,7 @@ executables:
87
87
  extensions: []
88
88
  extra_rdoc_files: []
89
89
  files:
90
+ - ".gitignore"
90
91
  - ".travis.yml"
91
92
  - Gemfile
92
93
  - Gemfile.lock