coney_island 0.1.2 → 0.1.3

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: 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