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