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 +4 -4
- data/lib/coney_island.rb +57 -1
- data/lib/coney_island/submitter.rb +31 -14
- data/lib/coney_island/version.rb +1 -1
- data/lib/coney_island/worker.rb +33 -22
- data/test/coney_island_test.rb +29 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/test.log +0 -0
- data/test/submitter_test.rb +4 -9
- data/test/worker_test.rb +2 -2
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fc75eee43a318be728acdf0b941206e100c76aa2
|
4
|
+
data.tar.gz: b94cbb25dcbfba834707f0a4fa1cc5e9056d435e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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
|
-
|
22
|
-
|
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
|
-
|
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
|
-
|
45
|
+
Rails.logger.info("using single connection to RabbitMQ")
|
46
|
+
ConeyIsland.handle_connection(Rails.logger)
|
43
47
|
@exchange = ConeyIsland.exchange
|
44
48
|
else
|
45
|
-
|
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.
|
52
|
-
self.
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
-
|
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)
|
data/lib/coney_island/version.rb
CHANGED
data/lib/coney_island/worker.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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|
|
data/test/coney_island_test.rb
CHANGED
@@ -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
|
data/test/submitter_test.rb
CHANGED
@@ -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
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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.
|
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
|
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.
|
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-
|
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
|