toiler 0.5.1.pre9 → 0.5.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: 61292f1454428dae50787cb722201108250b136b
4
- data.tar.gz: 004ab4f17d203ca40b4f4f74fac79ba52f0449cd
3
+ metadata.gz: 1defeb7538e17ae38a0028878f07de278ad6fc34
4
+ data.tar.gz: 8a233a42c1776663ce3dd04d5f22e318587de752
5
5
  SHA512:
6
- metadata.gz: d9a8db8fcfd8c5986cf096a4d8f598bdef0a8a35f8da739fdecce50f6dc8976a822cd86f6f5caf8ad4d3d51257eb4fc5591dca29a8b91acc42978af8451711b5
7
- data.tar.gz: 1c2552b393d6fde181b4d81fa80a971aa8f2076c44f3f556da2957a9453a5d13df8abaa0a1f90facc097a072592646033f4391682a12756001a5e38c736e2063
6
+ metadata.gz: bc096c97a2efca04256aaf8d7895d73bde781b2a6c961de35a0a188b7db14a92e0eaabb970040f37a8e1063b8de8801f3bae6fd6d38e4fb42937a9f9e9a06acb
7
+ data.tar.gz: 41dc4911884dc11ac9df2b1e55d438effda0c9a752b916699e568e206e3ac6fca5cae0d0551ac306f1aa35dc93f1fc7353e17a873f53516f502da8f38a131a8f
data/Gemfile.lock CHANGED
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- toiler (0.5.1.pre7)
5
- aws-sdk-sqs (>= 1.0.0, < 2.0.0)
4
+ toiler (0.4.3)
5
+ aws-sdk-sqs (~> 1.0, >= 1.0.0)
6
6
  concurrent-ruby (~> 1.0, >= 1.0.0)
7
7
  concurrent-ruby-edge (~> 0.3, >= 0.3)
8
8
 
@@ -11,14 +11,14 @@ GEM
11
11
  specs:
12
12
  ast (2.4.0)
13
13
  aws-eventstream (1.0.1)
14
- aws-partitions (1.105.0)
15
- aws-sdk-core (3.31.0)
14
+ aws-partitions (1.100.0)
15
+ aws-sdk-core (3.24.1)
16
16
  aws-eventstream (~> 1.0)
17
17
  aws-partitions (~> 1.0)
18
18
  aws-sigv4 (~> 1.0)
19
19
  jmespath (~> 1.0)
20
- aws-sdk-sqs (1.7.0)
21
- aws-sdk-core (~> 3, >= 3.26.0)
20
+ aws-sdk-sqs (1.4.0)
21
+ aws-sdk-core (~> 3)
22
22
  aws-sigv4 (~> 1.0)
23
23
  aws-sigv4 (1.0.3)
24
24
  concurrent-ruby (1.0.5)
@@ -10,38 +10,49 @@ module Toiler
10
10
  FETCH_LIMIT = 10
11
11
 
12
12
  attr_accessor :queue, :wait, :visibility_timeout, :free_processors,
13
- :executing, :waiting_messages, :concurrency
13
+ :scheduled, :executing, :polling
14
14
 
15
- def initialize(queue, client, count)
15
+ def initialize(queue, client)
16
16
  debug "Initializing Fetcher for queue #{queue}..."
17
17
  @queue = Toiler::Aws::Queue.new queue, client
18
- @wait = Toiler.options[:wait] || 60
19
- @free_processors = count
18
+ @wait = Toiler.options[:wait] || 20
19
+ @free_processors = Concurrent::AtomicFixnum.new(0)
20
20
  @batch = Toiler.worker_class_registry[queue].batch?
21
21
  @visibility_timeout = @queue.visibility_timeout
22
- @executing = false
23
- @waiting_messages = 0
24
- @concurrency = count
22
+ @scheduled = Concurrent::AtomicBoolean.new
23
+ @executing = Concurrent::AtomicBoolean.new
24
+ @polling = Concurrent::AtomicBoolean.new
25
25
  debug "Finished initializing Fetcher for queue #{queue}"
26
- tell :poll_messages
27
26
  end
28
27
 
29
28
  def default_executor
30
- Concurrent.global_fast_executor
29
+ Concurrent.global_io_executor
31
30
  end
32
31
 
33
32
  def on_message(msg)
34
- @executing = true
33
+ executing.make_true
35
34
  method, *args = msg
36
35
  send(method, *args)
37
36
  rescue StandardError => e
38
37
  error "Fetcher #{queue.name} raised exception #{e.class}: #{e.message}\n#{e.backtrace.join("\n")}"
39
38
  ensure
40
- @executing = false
39
+ executing.make_false
41
40
  end
42
41
 
43
42
  def executing?
44
- @executing
43
+ executing.value
44
+ end
45
+
46
+ def polling?
47
+ polling.value
48
+ end
49
+
50
+ def scheduled?
51
+ scheduled.value
52
+ end
53
+
54
+ def get_free_processors
55
+ free_processors.value
45
56
  end
46
57
 
47
58
  private
@@ -52,55 +63,46 @@ module Toiler
52
63
 
53
64
  def processor_finished
54
65
  debug "Fetcher #{queue.name} received processor finished signal..."
55
- @free_processors += 1
56
- tell :poll_messages
66
+ free_processors.increment
67
+ schedule_poll
57
68
  end
58
69
 
59
70
  def max_messages
60
- batch? ? FETCH_LIMIT : [FETCH_LIMIT, free_processors].min
71
+ batch? ? FETCH_LIMIT : [FETCH_LIMIT, free_processors.value].min
61
72
  end
62
73
 
63
- def poll_future(max_number_of_messages)
74
+ def poll_future
75
+
64
76
  Concurrent::Promises.future do
65
- queue.receive_messages message_attribute_names: %w[All],
77
+ queue.receive_messages attribute_names: %w(All),
78
+ message_attribute_names: %w(All),
66
79
  wait_time_seconds: wait,
67
- max_number_of_messages: max_number_of_messages
80
+ max_number_of_messages: max_messages
68
81
  end
69
82
  end
70
83
 
71
- def release_messages(messages)
72
- @waiting_messages -= messages
73
- end
74
-
75
84
  def poll_messages
76
- return unless should_poll?
77
-
78
- max_number_of_messages = max_messages
79
- return if waiting_messages > 0 && !full_batch?(max_number_of_messages)
80
-
81
- @waiting_messages += max_number_of_messages
82
-
83
- debug "Fetcher #{queue.name} polling messages..."
84
- future = poll_future max_number_of_messages
85
- future.on_rejection! do
86
- tell [:release_messages, max_number_of_messages]
87
- tell :poll_messages
85
+ return unless polling.make_true
86
+ poll_future.on_rejection! do
87
+ polling.make_false
88
+ scheduled.make_false
89
+ tell :schedule_poll
88
90
  end
89
- future.on_fulfillment! do |msgs|
90
- tell [:assign_messages, msgs] if !msgs.nil? && !msgs.empty?
91
- tell [:release_messages, max_number_of_messages]
92
- tell :poll_messages
91
+ poll_future.on_fulfillment! do |msgs|
92
+ polling.make_false
93
+ scheduled.make_false
94
+ if !msgs.nil? && !msgs.empty?
95
+ tell [:assign_messages, msgs]
96
+ else
97
+ tell :schedule_poll
98
+ end
93
99
  end
94
-
95
- poll_messages if should_poll?
96
- end
97
-
98
- def should_poll?
99
- free_processors / 2 > waiting_messages
100
100
  end
101
101
 
102
- def full_batch?(max_number_of_messages)
103
- max_number_of_messages == FETCH_LIMIT || max_number_of_messages >= concurrency * 0.1
102
+ def schedule_poll
103
+ return unless free_processors.value > 0 && scheduled.make_true
104
+ debug "Fetcher #{queue.name} scheduling polling..."
105
+ tell :poll_messages
104
106
  end
105
107
 
106
108
  def processor_pool
@@ -111,9 +113,10 @@ module Toiler
111
113
  messages = [messages] if batch?
112
114
  messages.each do |m|
113
115
  processor_pool.tell [:process, visibility_timeout, m]
114
- @free_processors -= 1
116
+ free_processors.decrement
115
117
  end
116
118
  debug "Fetcher #{queue.name} assigned #{messages.count} messages"
119
+ tell :schedule_poll
117
120
  end
118
121
  end
119
122
  end
@@ -13,19 +13,17 @@ module Toiler
13
13
  def initialize(queue)
14
14
  @queue = queue
15
15
  @worker_class = Toiler.worker_class_registry[queue]
16
+ @fetcher = Toiler.fetcher queue
16
17
  @executing = Concurrent::AtomicBoolean.new
17
18
  @thread = nil
18
19
  init_options
20
+ processor_finished
19
21
  end
20
22
 
21
23
  def default_executor
22
24
  Concurrent.global_io_executor
23
25
  end
24
26
 
25
- def fetcher
26
- @fetcher ||= Toiler.fetcher queue
27
- end
28
-
29
27
  def on_message(msg)
30
28
  method, *args = msg
31
29
  send(method, *args)
@@ -91,16 +89,14 @@ module Toiler
91
89
 
92
90
  def visibility_extender(queue_visibility, sqs_msg, body)
93
91
  return unless auto_visibility_timeout?
94
-
95
- interval = [1, queue_visibility / 3].max
92
+ interval = [1,queue_visibility/3].max
96
93
  Concurrent::TimerTask.execute execution_interval: interval,
97
- timeout_interval: interval do |task|
94
+ timeout_interval: interval do
98
95
  begin
99
96
  sqs_msg.visibility_timeout = queue_visibility
100
97
  yield sqs_msg, body if block_given?
101
98
  rescue StandardError => e
102
- error "Processor #{queue} failed to extend visibility of message - #{e.class}: #{e.message}\n#{e.backtrace.join("\n")}"
103
- task.shutdown if e.message.include?('ReceiptHandle is invalid')
99
+ error "Processor #{queue} failed to extend visibility of message: #{e.message}\n#{e.backtrace.join("\n")}"
104
100
  end
105
101
  end
106
102
  end
@@ -120,7 +116,7 @@ module Toiler
120
116
  when :text, nil then sqs_msg.body
121
117
  else body_parser.load sqs_msg.body
122
118
  end
123
- rescue StandardError => e
119
+ rescue => e
124
120
  raise "Error parsing the message body: #{e.message}"
125
121
  end
126
122
  end
@@ -11,8 +11,8 @@ module Toiler
11
11
 
12
12
  def initialize
13
13
  @client = ::Aws::SQS::Client.new
14
- spawn_processors
15
14
  spawn_fetchers
15
+ spawn_processors
16
16
  end
17
17
 
18
18
  def on_message(_msg)
@@ -20,12 +20,10 @@ module Toiler
20
20
  end
21
21
 
22
22
  def spawn_fetchers
23
- Toiler.active_worker_class_registry.each do |queue, klass|
24
- count = klass.concurrency
23
+ Toiler.active_worker_class_registry.each do |queue, _klass|
25
24
  begin
26
25
  fetcher = Actor::Fetcher.spawn! name: "fetcher_#{queue}".to_sym,
27
- supervise: true,
28
- args: [queue, client, count]
26
+ supervise: true, args: [queue, client]
29
27
  Toiler.set_fetcher queue, fetcher
30
28
  rescue StandardError => e
31
29
  error "Failed to start Fetcher for queue #{queue}: #{e.message}\n#{e.backtrace.join("\n")}"
@@ -39,9 +37,8 @@ module Toiler
39
37
  count = klass.concurrency
40
38
  begin
41
39
  pool = Concurrent::Actor::Utils::Pool.spawn! name, count do |index|
42
- Actor::Processor.spawn name: "processor_#{queue}_#{index}".to_sym,
43
- supervise: true,
44
- args: [queue]
40
+ Actor::Processor.spawn name: "processor_#{queue}_#{index}".to_sym,
41
+ supervise: true, args: [queue]
45
42
  end
46
43
  Toiler.set_processor_pool queue, pool
47
44
  rescue StandardError => e
data/lib/toiler/cli.rb CHANGED
@@ -99,7 +99,7 @@ module Toiler
99
99
  processors = processor_pool.instance_variable_get(:@workers).collect{|w| w.send(:core).send(:context)}
100
100
  busy_processors = processors.count{|pr| pr.executing?}
101
101
  message = "Status for [queue:#{queue}]:"
102
- message += "\n[fetcher:#{fetcher.name}] [executing:#{fetcher.executing?}] [waiting_messages:#{fetcher.waiting_messages}] [free_processors:#{fetcher.free_processors}]"
102
+ message += "\n[fetcher:#{fetcher.name}] [executing:#{fetcher.executing?}] [polling:#{fetcher.polling?}] [scheduled:#{fetcher.scheduled?}] [free_processors:#{fetcher.get_free_processors}]"
103
103
  message += "\n[processor_pool:#{processor_pool.name}] [workers:#{processors.count}] [busy:#{busy_processors}]"
104
104
  processors.each do |processor|
105
105
  thread = processor.thread
@@ -1,4 +1,4 @@
1
1
  # Toiler Version
2
2
  module Toiler
3
- VERSION = '0.5.1.pre9'.freeze
3
+ VERSION = '0.5.1'.freeze
4
4
  end
@@ -7,16 +7,16 @@ RSpec.describe Toiler::Actor::Fetcher, type: :model do
7
7
 
8
8
  before do
9
9
  allow_any_instance_of(Toiler::Actor::Fetcher).to receive(:log).and_return(true)
10
- allow_any_instance_of(Toiler::Actor::Fetcher).to receive(:tell)
11
10
  allow_any_instance_of(Toiler::Aws::Queue).to receive(:visibility_timeout).and_return(100)
12
11
  allow(client).to receive(:get_queue_url).with(queue_name: 'default').and_return double(:queue, queue_url: 'http://aws.fake/queue')
13
12
  end
14
13
 
15
14
  describe "#new" do
16
15
  it 'completes sucessfully' do
17
- fetcher = described_class.new(queue, client, 1)
18
- expect(fetcher).to have_received(:tell).with(:poll_messages)
16
+ fetcher = described_class.new(queue, client)
17
+ expect(fetcher.polling?).to eq(false)
19
18
  expect(fetcher.executing?).to eq(false)
19
+ expect(fetcher.scheduled?).to eq(false)
20
20
  end
21
21
  end
22
22
  end
@@ -7,6 +7,7 @@ RSpec.describe Toiler::Actor::Processor, type: :model do
7
7
  describe "#new" do
8
8
  it 'initializes properly' do
9
9
  allow(Toiler).to receive(:fetcher).and_return(fetcher)
10
+ expect(fetcher).to receive(:tell).with(:processor_finished)
10
11
  processor = described_class.new('default')
11
12
  expect(processor.executing?).to eq(false)
12
13
  end
@@ -13,7 +13,7 @@ RSpec.describe Toiler::Actor::Supervisor, type: :model do
13
13
 
14
14
  Toiler.options.merge!(active_queues: ['default'])
15
15
  expect(::Aws::SQS::Client).to receive(:new).and_return(sqs_client)
16
- expect(Toiler::Actor::Fetcher).to receive(:spawn!).with(name: :fetcher_default, supervise: true, args: ['default', sqs_client, 1])
16
+ expect(Toiler::Actor::Fetcher).to receive(:spawn!).with(name: :fetcher_default, supervise: true, args: ['default', sqs_client])
17
17
  expect(Concurrent::Actor::Utils::Pool).to receive(:spawn!).with(:processor_pool_default, 1)
18
18
  supervisor = described_class.new
19
19
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: toiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1.pre9
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sebastian Schepens
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-25 00:00:00.000000000 Z
11
+ date: 2018-11-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -136,12 +136,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
136
136
  version: '0'
137
137
  required_rubygems_version: !ruby/object:Gem::Requirement
138
138
  requirements:
139
- - - ">"
139
+ - - ">="
140
140
  - !ruby/object:Gem::Version
141
- version: 1.3.1
141
+ version: '0'
142
142
  requirements: []
143
143
  rubyforge_project:
144
- rubygems_version: 2.6.11
144
+ rubygems_version: 2.5.2.1
145
145
  signing_key:
146
146
  specification_version: 4
147
147
  summary: Toiler is a super efficient AWS SQS thread based message processor