cottontail 0.1.1 → 0.1.2
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.
- data/README.md +2 -2
- data/lib/cottontail.rb +89 -69
- data/lib/cottontail/version.rb +1 -1
- metadata +2 -2
data/README.md
CHANGED
@@ -27,10 +27,10 @@ require 'bunny'
|
|
27
27
|
class Worker < Cottontail::Base
|
28
28
|
# configure the Bunny client with the default connection (host: "localhost", port: 5672)
|
29
29
|
# and with logging.
|
30
|
-
set :client, :logging => true
|
30
|
+
set :client, { :logging => true }
|
31
31
|
|
32
32
|
# Declare default direct exchange which is bound to all queues of the type `topic`
|
33
|
-
set :exchange, "", :type => :topic
|
33
|
+
set :exchange, [ "", { :type => :topic } ]
|
34
34
|
|
35
35
|
# Declare the `test` queue
|
36
36
|
set :queue, "test"
|
data/lib/cottontail.rb
CHANGED
@@ -37,39 +37,13 @@ module Cottontail
|
|
37
37
|
class << self
|
38
38
|
attr_reader :routes
|
39
39
|
|
40
|
-
# convenience method to start the instance
|
41
|
-
def run; new.run; end
|
42
|
-
|
43
|
-
# Reset the class
|
44
|
-
def reset!
|
45
|
-
@settings = {}
|
46
|
-
|
47
|
-
@errors = {}
|
48
|
-
@routes = {}
|
49
|
-
|
50
|
-
# default logger
|
51
|
-
set(:logger) { Logger.new(STDOUT) }
|
52
|
-
|
53
|
-
# retry settings
|
54
|
-
set(:retries) { true }
|
55
|
-
set(:delay_on_retry) { 2 }
|
56
|
-
|
57
|
-
# default subscribe loop
|
58
|
-
set :subscribe, {}, proc { |m| route! m }
|
59
|
-
|
60
|
-
# default bunny options
|
61
|
-
set :client, {}
|
62
|
-
set :exchange, "default", :type => :topic
|
63
|
-
set :queue, "default"
|
64
|
-
end
|
65
|
-
|
66
40
|
# Set runtime configuration
|
67
41
|
#
|
68
42
|
# @example
|
69
|
-
# set :
|
70
|
-
# set(:
|
71
|
-
def set( key,
|
72
|
-
@settings[ key ] = block ? block :
|
43
|
+
# set :logger, Logger.new(STDOUT)
|
44
|
+
# set(:logger) { Logger.new(STDOUT) } # will be called on first usage
|
45
|
+
def set( key, value = nil, &block )
|
46
|
+
@settings[ key ] = block ? block : value
|
73
47
|
end
|
74
48
|
|
75
49
|
# Override the standard subscribe loop
|
@@ -80,7 +54,7 @@ module Cottontail
|
|
80
54
|
# route! message
|
81
55
|
# end
|
82
56
|
def subscribe( options = {}, &block )
|
83
|
-
set :subscribe, options, compile!("subscribe", &block)
|
57
|
+
set :subscribe, [options, compile!("subscribe", &block)]
|
84
58
|
end
|
85
59
|
|
86
60
|
# Defines routing on class level
|
@@ -95,14 +69,20 @@ module Cottontail
|
|
95
69
|
|
96
70
|
# Define error handlers
|
97
71
|
#
|
98
|
-
# @example
|
72
|
+
# @example Generic route
|
73
|
+
# error do
|
74
|
+
# puts "an error occured"
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# @example Error on specific Exception
|
99
78
|
# error RouteNotFound do
|
100
79
|
# puts "Route not found for #{routing_key.inspect}"
|
101
80
|
# end
|
102
81
|
def error( *codes, &block )
|
103
82
|
codes << :default if codes.empty? # the default error handling
|
104
83
|
|
105
|
-
|
84
|
+
compiled = compile!("error_#{codes.join("_")}", &block)
|
85
|
+
codes.each { |c| @errors[c] = compiled }
|
106
86
|
end
|
107
87
|
|
108
88
|
# Route on class level (handy for testing)
|
@@ -129,52 +109,80 @@ module Cottontail
|
|
129
109
|
# Retrieve the error block for the passed Exception class
|
130
110
|
#
|
131
111
|
# If no class matches, the default will be returned in case it has been set (else nil).
|
132
|
-
def
|
112
|
+
def error_for( klass )
|
133
113
|
@errors[klass] || @errors[:default]
|
134
114
|
end
|
135
115
|
|
116
|
+
# convenience method to start the instance
|
117
|
+
def run; new.run; end
|
136
118
|
|
137
|
-
|
119
|
+
# Reset the class
|
120
|
+
def reset!
|
121
|
+
@settings = {}
|
138
122
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
123
|
+
@errors = {}
|
124
|
+
@routes = {}
|
125
|
+
|
126
|
+
# default logger
|
127
|
+
set :logger, Logger.new(STDOUT)
|
128
|
+
|
129
|
+
# retry settings
|
130
|
+
set :retries, true
|
131
|
+
set :delay_on_retry, 2
|
143
132
|
|
144
|
-
|
145
|
-
|
146
|
-
define_method name, &block
|
147
|
-
method = instance_method name
|
148
|
-
remove_method name
|
133
|
+
# default subscribe loop
|
134
|
+
set :subscribe, [{}, proc { |m| route! m }]
|
149
135
|
|
150
|
-
|
136
|
+
# default bunny options
|
137
|
+
set :client, {}
|
138
|
+
set :exchange, ["default", {:type => :topic}]
|
139
|
+
set :queue, "default"
|
151
140
|
end
|
152
141
|
|
142
|
+
|
143
|
+
private
|
144
|
+
|
145
|
+
def inherited( subclass )
|
146
|
+
subclass.reset!
|
147
|
+
super
|
148
|
+
end
|
149
|
+
|
150
|
+
# compiles a given proc to an unbound method to be called later on a different binding
|
151
|
+
def compile!( name, &block )
|
152
|
+
define_method name, &block
|
153
|
+
method = instance_method name
|
154
|
+
remove_method name
|
155
|
+
|
156
|
+
block.arity == 0 ? proc { |a,p| method.bind(a).call } : proc { |a,*p| method.bind(a).call(*p) }
|
157
|
+
end
|
158
|
+
|
153
159
|
end
|
154
160
|
|
161
|
+
|
155
162
|
def initialize
|
156
163
|
reset!
|
157
164
|
end
|
158
165
|
|
159
166
|
# Starts the consumer service and enters the subscribe loop.
|
160
167
|
def run
|
168
|
+
# establish connection and bind routing keys
|
161
169
|
logger.debug "[Cottontail] Connecting to client"
|
162
|
-
@client = Bunny.new(
|
170
|
+
@client = Bunny.new( settings(:client) )
|
163
171
|
@client.start
|
164
172
|
|
165
173
|
logger.debug "[Cottontail] Declaring exchange"
|
166
174
|
exchange = @client.exchange( *settings(:exchange) )
|
167
175
|
|
168
176
|
logger.debug "[Cottontail] Declaring queue"
|
169
|
-
queue = @client.queue(
|
177
|
+
queue = @client.queue( settings(:queue) )
|
170
178
|
|
171
179
|
routes.keys.each do |key|
|
172
180
|
logger.debug "[Cottontail] Binding #{key.inspect} to exchange"
|
173
181
|
queue.bind( exchange, :key => key )
|
174
182
|
end
|
175
183
|
|
176
|
-
|
177
|
-
subscribe! queue
|
184
|
+
# enter the subscribe loop
|
185
|
+
subscribe!( queue )
|
178
186
|
rescue => e
|
179
187
|
@client.stop if @client
|
180
188
|
reset!
|
@@ -189,35 +197,26 @@ module Cottontail
|
|
189
197
|
retry
|
190
198
|
end
|
191
199
|
|
192
|
-
#
|
200
|
+
# Performs the routing of the given AMQP message
|
201
|
+
#
|
202
|
+
# The method will raise an error if no route was found or an exception
|
203
|
+
# was raised within matched routing block.
|
193
204
|
def route!( message )
|
194
205
|
@message = message
|
195
|
-
process!
|
196
|
-
rescue => err
|
197
|
-
@last_error = err
|
198
206
|
|
199
|
-
if
|
200
|
-
|
207
|
+
if block = routes[routing_key]
|
208
|
+
block.call(self)
|
201
209
|
else
|
202
|
-
|
210
|
+
raise Cottontail::RouteNotFound.new(routing_key)
|
203
211
|
end
|
204
212
|
end
|
205
213
|
|
206
214
|
|
207
215
|
private
|
208
216
|
|
209
|
-
|
210
|
-
key = @message[:delivery_details][:routing_key]
|
211
|
-
|
212
|
-
raise Cottontail::RouteNotFound.new(key) unless block = routes[key]
|
213
|
-
block.call(self)
|
214
|
-
end
|
215
|
-
|
217
|
+
# Retrieve routes
|
216
218
|
def routes; self.class.routes; end
|
217
219
|
|
218
|
-
# Retrieve errors
|
219
|
-
def errors(code); self.class.errors(code); end
|
220
|
-
|
221
220
|
# Retrieve settings
|
222
221
|
def settings(key); self.class.settings(key); end
|
223
222
|
|
@@ -231,17 +230,39 @@ module Cottontail
|
|
231
230
|
prepare_client_settings!
|
232
231
|
end
|
233
232
|
|
233
|
+
# Handles the subscribe loop on the queue.
|
234
234
|
def subscribe!( queue )
|
235
|
+
logger.debug "[Cottontail] Entering subscribe loop"
|
236
|
+
|
235
237
|
options, block = settings(:subscribe)
|
238
|
+
queue.subscribe( options ) do |m|
|
239
|
+
with_error_handling!( m, &block )
|
240
|
+
end
|
241
|
+
end
|
236
242
|
|
237
|
-
|
243
|
+
# Gracefully handles the given message.
|
244
|
+
#
|
245
|
+
# @param [Message] m The RabbitMQ message to be handled
|
246
|
+
def with_error_handling!( m, &block )
|
247
|
+
block.call(self, m)
|
248
|
+
rescue => err
|
249
|
+
@last_error = err
|
250
|
+
|
251
|
+
if block = self.class.error_for(err.class)
|
252
|
+
block.call(self)
|
253
|
+
else
|
254
|
+
# if no defined exception handling block could be found, then re-raise
|
255
|
+
raise( err, caller )
|
256
|
+
end
|
257
|
+
ensure
|
258
|
+
@last_error = nil # unset error after handling
|
238
259
|
end
|
239
260
|
|
240
261
|
# The bunny gem itself is not able to handle multiple hosts - although multiple RabbitMQ instances may run in parralel.
|
241
262
|
#
|
242
263
|
# You may pass :hosts as option when settings the client in order to cycle through them in case a connection was lost.
|
243
264
|
def prepare_client_settings!
|
244
|
-
return {} unless options = settings(:client)
|
265
|
+
return {} unless options = settings(:client)
|
245
266
|
|
246
267
|
if hosts = options[:hosts]
|
247
268
|
host, port = hosts.shift
|
@@ -253,7 +274,6 @@ module Cottontail
|
|
253
274
|
options
|
254
275
|
end
|
255
276
|
|
256
|
-
|
257
277
|
public
|
258
278
|
|
259
279
|
# === Perform the initial setup
|
data/lib/cottontail/version.rb
CHANGED
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: cottontail
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.1.
|
5
|
+
version: 0.1.2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Rudolf Schmidt
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2012-02-
|
13
|
+
date: 2012-02-29 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: bunny
|