coney_island 0.1.2 → 0.1.3

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: c56c9ef5e0a701dbf1b5dc6d574158eb603c5b39
4
- data.tar.gz: 78a9a731b07471b9591b43774805622601b6fc66
3
+ metadata.gz: fc75eee43a318be728acdf0b941206e100c76aa2
4
+ data.tar.gz: b94cbb25dcbfba834707f0a4fa1cc5e9056d435e
5
5
  SHA512:
6
- metadata.gz: fcac6ce63736e212e822371306d7a4d57b5d0b5571f8716086d8d2d725f7846424b936e554593df95c56c2af1bd5912359ca6e5946ce40a905adae74ab44a083
7
- data.tar.gz: f3fb209da6ffc4acec4ba8921b1523931f426e6bbdef62f9800562981bc14fecfde5ab7453da8f9bf0fdd295a45f5f42c7c72a7dea8e3f9e125cbac766435702
6
+ metadata.gz: 4eb709dc6cdf88655300a98fffec366b083756db5bb1cc4c60f268f8d1b444a7ba101dab5d0dfb4465cdb792ce65af9d287f4f7d7ef6ada3ae3facb3cea0f28a
7
+ data.tar.gz: 2bff91ac4362619b7eeb1e9111ae6c8983a1675199dd8b2c32e2c835fbc21e560233057d3c867dec5cf2a1c6324594a076124c36b314a4940f39bb8c1a913338
data/lib/coney_island.rb CHANGED
@@ -16,8 +16,52 @@ module ConeyIsland
16
16
  @amqp_parameters
17
17
  end
18
18
 
19
- def self.handle_connection
19
+ def self.tcp_connection_retries=(number)
20
+ @tcp_connection_retries = number
21
+ end
22
+
23
+ def self.tcp_connection_retries
24
+ @tcp_connection_retries
25
+ end
26
+
27
+ def self.tcp_connection_retry_limit=(limit)
28
+ @tcp_connection_retry_limit = limit
29
+ end
30
+
31
+ def self.tcp_connection_retry_limit
32
+ @tcp_connection_retry_limit ||= 6
33
+ end
34
+
35
+ def self.tcp_connection_retry_interval=(interval)
36
+ @tcp_connection_retry_interval = interval
37
+ end
38
+
39
+ def self.tcp_connection_retry_interval
40
+ @tcp_connection_retry_interval ||= 10
41
+ end
42
+
43
+ def self.handle_connection(log)
20
44
  @connection ||= AMQP.connect(self.amqp_parameters)
45
+ rescue AMQP::TCPConnectionFailed => e
46
+ self.tcp_connection_retries ||= 0
47
+ self.tcp_connection_retries += 1
48
+ if self.tcp_connection_retries >= self.tcp_connection_retry_limit
49
+ message = "Failed to connect to RabbitMQ #{self.tcp_connection_retry_limit} times, bailing out"
50
+ log.error(message)
51
+ self.poke_the_badger(e, {
52
+ code_source: 'ConeyIsland.handle_connection',
53
+ reason: message}
54
+ )
55
+ else
56
+ message = "Failed to connecto to RabbitMQ Attempt ##{self.tcp_connection_retries} time(s), trying again in #{self.tcp_connection_retry_interval} seconds..."
57
+ log.error(message)
58
+ self.poke_the_badger(e, {
59
+ code_source: 'ConeyIsland.handle_connection',
60
+ reason: message})
61
+ sleep(self.tcp_connection_retry_interval)
62
+ retry
63
+ end
64
+ else
21
65
  @channel ||= AMQP::Channel.new(@connection)
22
66
  self.exchange = @channel.topic('coney_island')
23
67
  end
@@ -86,6 +130,18 @@ module ConeyIsland
86
130
  def self.submit(*args)
87
131
  ConeyIsland::Submitter.submit(*args)
88
132
  end
133
+
134
+ def self.poke_the_badger(message, context, attempts = 1)
135
+ Timeout::timeout(3) do
136
+ @notifier.notify(message, context)
137
+ end
138
+ rescue
139
+ if attempts <= 3
140
+ attempts += 1
141
+ retry
142
+ end
143
+ end
144
+
89
145
  end
90
146
 
91
147
  require 'coney_island/notifiers/honeybadger_notifier'
@@ -18,10 +18,13 @@ module ConeyIsland
18
18
  end
19
19
 
20
20
  def self.submit!(args)
21
- if @run_inline
22
- self.handle_publish(args)
21
+ self.handle_connection unless @run_inline
22
+ if :all_cached_jobs == args
23
+ RequestStore.store[:jobs].delete_if do |job_args|
24
+ self.publish_job(job_args)
25
+ end
23
26
  else
24
- self.handle_publish(args)
27
+ self.publish_job(args)
25
28
  end
26
29
  end
27
30
 
@@ -39,24 +42,38 @@ module ConeyIsland
39
42
 
40
43
  def self.handle_connection
41
44
  if ConeyIsland.single_amqp_connection?
42
- ConeyIsland.handle_connection
45
+ Rails.logger.info("using single connection to RabbitMQ")
46
+ ConeyIsland.handle_connection(Rails.logger)
43
47
  @exchange = ConeyIsland.exchange
44
48
  else
45
- @connection ||= AMQP.connect(self.amqp_parameters)
46
- @channel ||= AMQP::Channel.new(@connection)
47
- @exchange = @channel.topic('coney_island')
49
+ self.submitter_connection
48
50
  end
49
51
  end
50
52
 
51
- def self.handle_publish(args)
52
- self.handle_connection unless @run_inline
53
- if :all_cached_jobs == args
54
- RequestStore.store[:jobs].delete_if do |job_args|
55
- self.publish_job(job_args)
56
- end
53
+ def self.submitter_connection
54
+ @connection ||= AMQP.connect(self.amqp_parameters)
55
+ rescue AMQP::TCPConnectionFailed => e
56
+ @tcp_connection_retries ||= 0
57
+ @tcp_connection_retries += 1
58
+ if @tcp_connection_retries >= 6
59
+ message = "Failed to connect to RabbitMQ 6 times, bailing out"
60
+ Rails.logger.error(message)
61
+ ConeyIsland.poke_the_badger(e, {
62
+ code_source: 'ConeyIsland::Submitter.submitter_connection',
63
+ reason: message}
64
+ )
57
65
  else
58
- self.publish_job(args)
66
+ message = "Failed to connecto to RabbitMQ Attempt ##{@tcp_connection_retries} time(s), trying again in 10 seconds..."
67
+ Rails.logger.error(message)
68
+ ConeyIsland.poke_the_badger(e, {
69
+ code_source: 'ConeyIsland::Submitter.submitter_connection',
70
+ reason: message})
71
+ sleep(10)
72
+ retry
59
73
  end
74
+ else
75
+ @channel ||= AMQP::Channel.new(@connection)
76
+ @exchange = @channel.topic('coney_island')
60
77
  end
61
78
 
62
79
  def self.publish_job(args)
@@ -1,3 +1,3 @@
1
1
  module ConeyIsland
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
@@ -66,17 +66,41 @@ module ConeyIsland
66
66
 
67
67
  def self.handle_connection
68
68
  if ConeyIsland.single_amqp_connection?
69
- ConeyIsland.handle_connection
69
+ ConeyIsland.handle_connection(self.log)
70
70
  @exchange = ConeyIsland.exchange
71
71
  @channel = ConeyIsland.channel
72
72
  else
73
- puts self.amqp_parameters
74
- @connection ||= AMQP.connect(self.amqp_parameters)
75
- @channel ||= AMQP::Channel.new(@connection)
76
- @exchange = @channel.topic('coney_island')
73
+ self.worker_connection
77
74
  end
78
75
  end
79
76
 
77
+ def self.worker_connection
78
+ @connection ||= AMQP.connect(self.amqp_parameters)
79
+ rescue AMQP::TCPConnectionFailed => e
80
+ @tcp_connection_retries ||= 0
81
+ @tcp_connection_retries += 1
82
+ if @tcp_connection_retries >= 6
83
+ message = "Failed to connect to RabbitMQ 6 times, bailing out"
84
+ self.log.error(message)
85
+ ConeyIsland.poke_the_badger(e, {
86
+ code_source: 'ConeyIsland::Worker.worker_connection',
87
+ reason: message}
88
+ )
89
+ else
90
+ message = "Failed to connecto to RabbitMQ Attempt ##{@tcp_connection_retries} time(s), trying again in 10 seconds..."
91
+ self.log.error(message)
92
+ ConeyIsland.poke_the_badger(e, {
93
+ code_source: 'ConeyIsland::Worker.worker_connection',
94
+ reason: message})
95
+ sleep(10)
96
+ retry
97
+ end
98
+ else
99
+ @channel ||= AMQP::Channel.new(@connection)
100
+ @exchange = @channel.topic('coney_island')
101
+ end
102
+
103
+
80
104
  def self.start
81
105
  @child_count.times do
82
106
  child_pid = Process.fork
@@ -130,9 +154,9 @@ module ConeyIsland
130
154
  self.handle_job(metadata,args,job_id)
131
155
  end
132
156
  rescue Timeout::Error => e
133
- self.poke_the_badger(e, {code_source: 'ConeyIsland', job_payload: args, reason: 'timeout in subscribe code before calling job method'})
157
+ ConeyIsland.poke_the_badger(e, {code_source: 'ConeyIsland', job_payload: args, reason: 'timeout in subscribe code before calling job method'})
134
158
  rescue Exception => e
135
- self.poke_the_badger(e, {code_source: 'ConeyIsland', job_payload: args})
159
+ ConeyIsland.poke_the_badger(e, {code_source: 'ConeyIsland', job_payload: args})
136
160
  self.log.error("ConeyIsland code error, not application code:\n#{e.inspect}\nARGS: #{args}")
137
161
  end
138
162
  end
@@ -149,7 +173,7 @@ module ConeyIsland
149
173
  if self.job_attempts[job_id] >= 3
150
174
  self.log.error("Request #{job_id} timed out after #{timeout} seconds, bailing out after 3 attempts")
151
175
  self.finalize_job(metadata,job_id)
152
- self.poke_the_badger(e, {work_queue: @ticket, job_payload: args, reason: 'Bailed out after 3 attempts'})
176
+ ConeyIsland.poke_the_badger(e, {work_queue: @ticket, job_payload: args, reason: 'Bailed out after 3 attempts'})
153
177
  else
154
178
  self.log.error("Request #{job_id} timed out after #{timeout} seconds on attempt number #{self.job_attempts[job_id]}, retrying...")
155
179
  self.job_attempts[job_id] += 1
@@ -157,7 +181,7 @@ module ConeyIsland
157
181
  end
158
182
  end
159
183
  rescue Exception => e
160
- self.poke_the_badger(e, {work_queue: @ticket, job_payload: args})
184
+ ConeyIsland.poke_the_badger(e, {work_queue: @ticket, job_payload: args})
161
185
  self.log.error("Error executing #{args['klass']}##{args['method_name']} #{job_id} for id #{args['instance_id']} with args #{args}:")
162
186
  self.log.error(e.message)
163
187
  self.log.error(e.backtrace.join("\n"))
@@ -191,19 +215,6 @@ module ConeyIsland
191
215
  self.job_attempts.delete job_id
192
216
  end
193
217
 
194
- def self.poke_the_badger(message, context, attempts = 1)
195
- begin
196
- Timeout::timeout(3) do
197
- @notifier.notify(message, context)
198
- end
199
- rescue
200
- if attempts <= 3
201
- attempts += 1
202
- self.poke_the_badger(message, context, attempts)
203
- end
204
- end
205
- end
206
-
207
218
  def self.shutdown(signal)
208
219
  shutdown_time = Time.now
209
220
  @child_pids.each do |child_pid|
@@ -2,12 +2,26 @@ require 'test_helper'
2
2
 
3
3
  class ConeyIslandTest < MiniTest::Test
4
4
  describe "ConeyIsland running jobs" do
5
+
6
+ def force_tcp_error
7
+ lambda do |params|
8
+ @attempts ||= 0
9
+ @attempts += 1
10
+ if @attempts == 1
11
+ raise AMQP::TCPConnectionFailed.new({host: '127.0.0.1'})
12
+ else
13
+ return true
14
+ end
15
+ end
16
+ end
17
+
5
18
  it "runs inline" do
6
19
  ConeyIsland.run_inline
7
20
  my_array = []
8
21
  ConeyIsland.submit(TestModel, :add_to_list, args: [my_array])
9
22
  my_array.first.must_equal 'Added one!'
10
23
  end
24
+
11
25
  it "caches jobs" do
12
26
  ConeyIsland.run_inline
13
27
  my_array = []
@@ -19,5 +33,20 @@ class ConeyIslandTest < MiniTest::Test
19
33
  my_array.first.must_equal 'Added one!'
20
34
  ConeyIsland.stop_caching_jobs
21
35
  end
36
+
37
+ it "retries on TCP connection errors" do
38
+ ConeyIsland.stop_running_inline
39
+ ConeyIsland.tcp_connection_retry_interval = 0
40
+ @fake_channel = MiniTest::Mock.new
41
+ @fake_channel.expect :topic, nil, [String]
42
+ AMQP::Channel.stub(:new,@fake_channel) do
43
+ AMQP.stub(:connect, force_tcp_error) do
44
+ ConeyIsland.handle_connection(Logger.new(File.open(File::NULL, "w")))
45
+ end
46
+ end
47
+ @fake_channel.verify
48
+ ConeyIsland.tcp_connection_retries.must_equal 1
49
+ end
50
+
22
51
  end
23
52
  end
File without changes
File without changes
@@ -17,17 +17,12 @@ class SubmitterTest < MiniTest::Test
17
17
  it "publishes the job to the message bus" do
18
18
  @exchange = Minitest::Mock.new
19
19
  @exchange.expect :publish, nil, [String,Hash]
20
- @next_tick = Minitest::Mock.new
21
- @next_tick.expect :call, nil, []
22
- EventMachine.stub(:next_tick, @next_tick) do
23
- ConeyIsland::Submitter.stub(:handle_connection, nil) do
24
- ConeyIsland::Submitter.stub(:exchange, @exchange) do
25
- ConeyIsland::Submitter.stop_running_inline
26
- ConeyIsland::Submitter.submit(TestModel, :add_to_list, args: [[]])
27
- end
20
+ ConeyIsland::Submitter.stub(:handle_connection, nil) do
21
+ ConeyIsland::Submitter.stub(:exchange, @exchange) do
22
+ ConeyIsland::Submitter.stop_running_inline
23
+ ConeyIsland::Submitter.submit(TestModel, :add_to_list, args: [[]])
28
24
  end
29
25
  end
30
- @next_tick.verify
31
26
  @exchange.verify
32
27
  end
33
28
  end
data/test/worker_test.rb CHANGED
@@ -13,7 +13,7 @@ class WorkerTest < MiniTest::Test
13
13
  ConeyIsland::Worker.handle_job(@metadata,{
14
14
  'klass' => 'TestModel',
15
15
  'method_name' => :take_too_long,
16
- 'timeout' => 0.01
16
+ 'timeout' => 0.0001
17
17
  },'my_job_id')
18
18
  end
19
19
  ConeyIsland::Worker.job_attempts['my_job_id'].must_equal 3
@@ -21,7 +21,7 @@ class WorkerTest < MiniTest::Test
21
21
  it "sends other exeptions to a notification service" do
22
22
  @poke_the_badger = MiniTest::Mock.new
23
23
  @poke_the_badger.expect :call, nil, [Exception,Hash]
24
- ConeyIsland::Worker.stub(:poke_the_badger,@poke_the_badger) do
24
+ ConeyIsland.stub(:poke_the_badger,@poke_the_badger) do
25
25
  ConeyIsland::Worker.handle_job(@metadata,{
26
26
  'klass' => 'TestModel',
27
27
  'method_name' => :throw_an_error
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coney_island
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Draut
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-10-01 00:00:00.000000000 Z
12
+ date: 2014-10-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -144,6 +144,8 @@ files:
144
144
  - test/dummy/config/locales/en.yml
145
145
  - test/dummy/config/routes.rb
146
146
  - test/dummy/config/secrets.yml
147
+ - test/dummy/db/test.sqlite3
148
+ - test/dummy/log/test.log
147
149
  - test/dummy/public/404.html
148
150
  - test/dummy/public/422.html
149
151
  - test/dummy/public/500.html
@@ -207,6 +209,8 @@ test_files:
207
209
  - test/dummy/config/routes.rb
208
210
  - test/dummy/config/secrets.yml
209
211
  - test/dummy/config.ru
212
+ - test/dummy/db/test.sqlite3
213
+ - test/dummy/log/test.log
210
214
  - test/dummy/public/404.html
211
215
  - test/dummy/public/422.html
212
216
  - test/dummy/public/500.html