stooge 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/HISTORY.md +10 -0
- data/LICENSE +20 -0
- data/README.md +80 -0
- data/Rakefile +11 -0
- data/lib/stooge.rb +248 -0
- data/lib/stooge/handler.rb +52 -0
- data/lib/stooge/version.rb +3 -0
- data/lib/stooge/work_queue.rb +74 -0
- data/lib/stooge/worker.rb +61 -0
- data/spec/stooge_spec.rb +9 -0
- data/stooge.gemspec +26 -0
- metadata +104 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm 1.9.3@stooge --create
|
data/Gemfile
ADDED
data/HISTORY.md
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
|
2
|
+
### 0.1.0 (2012-03-09)
|
3
|
+
|
4
|
+
* Implemented same basic feature set as Minion (i.e. work queues)
|
5
|
+
* Added ability to easily test job handlers
|
6
|
+
* Made both #enqueue and #job asynchronous
|
7
|
+
* Changed from using Bunny to the using official AMQP gem
|
8
|
+
* Improved error handling logic and logging
|
9
|
+
* Handling of message content types (JSON is still default)
|
10
|
+
* Added reconnect to broker on connection failure support
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Niklas Holmgren, Sutajio
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
Stooge
|
2
|
+
======
|
3
|
+
|
4
|
+
Stooge is a fully EventMachine enabled DSL for interacting with an AMQP broker. Heavily inspired by Minion (but fresher and completely asynchronous).
|
5
|
+
|
6
|
+
Setup
|
7
|
+
-----
|
8
|
+
|
9
|
+
Assuming you already have an AMQP broker installed:
|
10
|
+
|
11
|
+
$ gem install stooge
|
12
|
+
|
13
|
+
You can configure the address to the broker using the ```AMQP_URL``` environment variable, or programmatically like this:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
Stooge.amqp_url = 'amqp://johndoe:abc123@localhost/my_vhost'
|
17
|
+
```
|
18
|
+
|
19
|
+
The default if not specified is ```amqp://guest:guest@localhost/```.
|
20
|
+
|
21
|
+
Example usage
|
22
|
+
-------------
|
23
|
+
|
24
|
+
To process a job add the following to a file called ```worker.rb``` and run it with ```ruby worker.rb```. Stooge will start an EventMachine loop that waits for AMQP messages and processes matching jobs until you send ```SIG_INT``` or ```SIG_TERM``` to it.
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
require 'stooge'
|
28
|
+
|
29
|
+
Stooge.job('example.puts') do |args|
|
30
|
+
puts args['message']
|
31
|
+
end
|
32
|
+
```
|
33
|
+
|
34
|
+
To push a job onto a queue you call ```Stooge.enqueue``` with the name of the work queue and the data you want to process. The data needs to be JSON serializable and can be for example a hash.
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
require 'stooge'
|
38
|
+
|
39
|
+
EM.run do
|
40
|
+
Stooge.enqueue('example.puts', :message => 'Hello, world!')
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
Error handling
|
45
|
+
--------------
|
46
|
+
|
47
|
+
When an error is thrown in a job handler, the job is requeued to be done later and the Stooge process exits. If you define an error handler, however, the error handler is run and the job is removed from the queue.
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
Stooge.error do |e|
|
51
|
+
puts "got an error! #{e}"
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
Logging
|
56
|
+
-------
|
57
|
+
|
58
|
+
Stooge logs to stdout via ```puts```. You can specify a custom logger like this:
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
Stooge.logger do |msg|
|
62
|
+
puts msg
|
63
|
+
end
|
64
|
+
```
|
65
|
+
|
66
|
+
Testing
|
67
|
+
-------
|
68
|
+
|
69
|
+
To test the business logic in your job handler you can use the ```Stooge.run_handler``` helper method:
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
Stooge.run_handler('example.work', { :foo => 'bar' }).should == 42
|
73
|
+
```
|
74
|
+
|
75
|
+
The return value is the return value from executing the job handler block.
|
76
|
+
|
77
|
+
Author
|
78
|
+
------
|
79
|
+
|
80
|
+
Stooge was created by Niklas Holmgren (niklas@sutajio.se) with help from Martin Bruse (@zond) and released under the MIT license. Stooge is very much inspired by Minion (created by Orion Henry), Resque (created by Chris Wanstrath) and Stalker (created by Adam Wiggins).
|
data/Rakefile
ADDED
data/lib/stooge.rb
ADDED
@@ -0,0 +1,248 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'multi_json'
|
3
|
+
require 'amqp'
|
4
|
+
require 'em-synchrony'
|
5
|
+
require 'stooge/version'
|
6
|
+
require 'stooge/handler'
|
7
|
+
require 'stooge/work_queue'
|
8
|
+
require 'stooge/worker'
|
9
|
+
|
10
|
+
module Stooge
|
11
|
+
extend self
|
12
|
+
extend Stooge::WorkQueue
|
13
|
+
|
14
|
+
@@connection = nil
|
15
|
+
@@channel = nil
|
16
|
+
@@handlers = []
|
17
|
+
@@error_handler = Proc.new do |exception, handler, payload, metadata|
|
18
|
+
Stooge.log "#{handler.queue_name} failed: #{exception.inspect}"
|
19
|
+
raise exception
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Will return a URL to the AMQP broker to use. Will get this from the
|
24
|
+
# <code>ENV</code> variable <code>AMQP_URL</code> if present, or use the
|
25
|
+
# default which is "amqp://guest:guest@localhost/" (the same as the default
|
26
|
+
# for a local RabbitMQ install).
|
27
|
+
#
|
28
|
+
# @return [String] a URL to an AMQP broker.
|
29
|
+
#
|
30
|
+
def amqp_url
|
31
|
+
@@amqp_url ||= ENV["AMQP_URL"] || "amqp://guest:guest@localhost/"
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# Set the URL to the AMQP broker to use. The format of the URL should be
|
36
|
+
# "amqp://username:password@hostname/vhost" (vhost and username/password is
|
37
|
+
# optional).
|
38
|
+
#
|
39
|
+
def amqp_url=(url)
|
40
|
+
@@amqp_url = url
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Log message using the Stooge logger.
|
45
|
+
#
|
46
|
+
# @param [String] msg the message to log.
|
47
|
+
#
|
48
|
+
def log(msg)
|
49
|
+
@@logger ||= proc { |m| puts "#{Time.now} :stooge: #{m}" }
|
50
|
+
@@logger.call(msg)
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# Configure a custom logger for Stooge. The block gets yielded with the
|
55
|
+
# log message. You can do whatever you want with it. The default behaviour
|
56
|
+
# is to simply output to stdout.
|
57
|
+
#
|
58
|
+
# @param [Proc] block a {::Proc} to yield when a message needs to be logged.
|
59
|
+
# @yieldparam [String] msg the message to log.
|
60
|
+
#
|
61
|
+
def logger(&blk)
|
62
|
+
@@logger = blk
|
63
|
+
end
|
64
|
+
|
65
|
+
#
|
66
|
+
# Configure a global error handler for Stooge jobs. The block gets yielded
|
67
|
+
# when a job handler raises an exception. The default error handler simply
|
68
|
+
# logs the error and re-raises the exception. You can use this to for
|
69
|
+
# example re-queue a failed job or send email notifications when a job
|
70
|
+
# fails.
|
71
|
+
#
|
72
|
+
# If you don't raise an exception in the error handler the job will be
|
73
|
+
# acked with the broker and the broker will consider the job done and remove
|
74
|
+
# it from the queue. If you for some reason want to force the job to be
|
75
|
+
# acked even when you raise an error you can manually ack it before you
|
76
|
+
# raise the error, like this:
|
77
|
+
#
|
78
|
+
# Stooge.error do |exception, handler, payload, metadata|
|
79
|
+
# metadata.ack
|
80
|
+
# raise exception
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# @param [Proc] block a {::Proc} to yield when an error happens.
|
84
|
+
# @yieldparam [Exception] exception the exception object raised.
|
85
|
+
# @yieldparam [Stooge::Handler] handler the handler that failed.
|
86
|
+
# @yieldparam [Object] payload the message payload that was processed when
|
87
|
+
# the handler failed.
|
88
|
+
# @yieldparam [Hash] metadata the message metadata (headers, etc.)
|
89
|
+
#
|
90
|
+
def error(&blk)
|
91
|
+
@@error_handler = blk
|
92
|
+
end
|
93
|
+
|
94
|
+
#
|
95
|
+
# The global error handler.
|
96
|
+
#
|
97
|
+
# @return [Proc] the error handler block.
|
98
|
+
#
|
99
|
+
def error_handler
|
100
|
+
@@error_handler
|
101
|
+
end
|
102
|
+
|
103
|
+
#
|
104
|
+
# Start listening to for new jobs on all queues using the specified channel.
|
105
|
+
#
|
106
|
+
# @param [AMQP::Channel] channel an open AMQP channel
|
107
|
+
#
|
108
|
+
def start_handlers(channel)
|
109
|
+
@@handlers.each { |h| h.start(channel) }
|
110
|
+
end
|
111
|
+
|
112
|
+
#
|
113
|
+
# Add a new job handler. Used by {Stooge.job}.
|
114
|
+
#
|
115
|
+
# @param [Stooge::Handler] handler a handler object
|
116
|
+
#
|
117
|
+
def add_handler(handler)
|
118
|
+
@@handlers << handler
|
119
|
+
end
|
120
|
+
|
121
|
+
#
|
122
|
+
# Are there any job handlers defined? Used by {Stooge::Worker} to check if
|
123
|
+
# it should start a worker process.
|
124
|
+
#
|
125
|
+
# @return [Boolean] true or false
|
126
|
+
#
|
127
|
+
def handlers?
|
128
|
+
@@handlers.empty? == false
|
129
|
+
end
|
130
|
+
|
131
|
+
#
|
132
|
+
# Execute a handler block without going through AMQP at all. This is a
|
133
|
+
# helper method for use in tests. It allows you to test the business logic
|
134
|
+
# in a handler block without having to mess with the details of how Stooge
|
135
|
+
# works internally.
|
136
|
+
#
|
137
|
+
# Examples
|
138
|
+
#
|
139
|
+
# Stooge.run_handler('example.work', :foo => 'bar').should == 42
|
140
|
+
#
|
141
|
+
# @param [String] queue_name the name of the handler to run
|
142
|
+
# @param [Object] data message data to send to the handler as arguments
|
143
|
+
# @param [Hash] headers optional headers to send as second argument to the
|
144
|
+
# handler block
|
145
|
+
#
|
146
|
+
# @return the return value of the handler block
|
147
|
+
#
|
148
|
+
def run_handler(queue_name, data, headers = {})
|
149
|
+
@@handlers.each do |handler|
|
150
|
+
if handler.queue_name == queue_name
|
151
|
+
return handler.block.call(data, headers)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
#
|
157
|
+
# Will yield an open and ready connection.
|
158
|
+
#
|
159
|
+
# @param [Proc] block a {::Proc} to yield an open and ready connection to.
|
160
|
+
#
|
161
|
+
def with_connection(&block)
|
162
|
+
if @@connection.nil? || @@connection.status == :closed
|
163
|
+
@@connection = AMQP.connect(amqp_config)
|
164
|
+
@@connection.on_tcp_connection_loss do
|
165
|
+
Stooge.log "[network failure] trying to reconnect..."
|
166
|
+
@@connection.reconnect
|
167
|
+
end
|
168
|
+
@@connection.on_recovery do
|
169
|
+
Stooge.log "connection with broker recovered"
|
170
|
+
end
|
171
|
+
@@connection.on_error do |ch, connection_close|
|
172
|
+
raise connection_close.reply_text
|
173
|
+
end
|
174
|
+
end
|
175
|
+
@@connection.on_open do
|
176
|
+
yield @@connection
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
#
|
181
|
+
# Will yield an open and ready channel.
|
182
|
+
#
|
183
|
+
# @param [Proc] block a {::Proc} to yield an open and ready channel to.
|
184
|
+
#
|
185
|
+
def with_channel(&block)
|
186
|
+
with_connection do |connection|
|
187
|
+
if @@channel.nil? || @@channel.status == :closed
|
188
|
+
@@channel = AMQP::Channel.new(connection, AMQP::Channel.next_channel_id, channel_options)
|
189
|
+
@@channel.on_error do |ch, channel_close|
|
190
|
+
Stooge.log "channel-level exception: code = #{channel_close.reply_code}, message = #{channel_close.reply_text}"
|
191
|
+
end
|
192
|
+
end
|
193
|
+
@@channel.once_open do
|
194
|
+
yield @@channel
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
# Start a {::Stooge} worker that consumes messages from the AMQP broker.
|
200
|
+
def start!
|
201
|
+
EM.synchrony do
|
202
|
+
with_channel do |channel|
|
203
|
+
start_handlers(channel)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Will stop and deactivate {::Stooge}.
|
209
|
+
def stop!
|
210
|
+
EM.next_tick do
|
211
|
+
with_channel do |channel|
|
212
|
+
channel.close
|
213
|
+
end
|
214
|
+
@@channel = nil
|
215
|
+
with_connection do |connection|
|
216
|
+
connection.close
|
217
|
+
end
|
218
|
+
@@connection = nil
|
219
|
+
EM.stop
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
private
|
224
|
+
|
225
|
+
# Will return the default options to use when creating channels.
|
226
|
+
def channel_options
|
227
|
+
@channel_options ||= {
|
228
|
+
:prefetch => 1,
|
229
|
+
:auto_recovery => true
|
230
|
+
}
|
231
|
+
end
|
232
|
+
|
233
|
+
# Will return the default options when connecting to the AMQP broker.
|
234
|
+
# Uses the URL from {#amqp_url} to construct these options.
|
235
|
+
def amqp_config
|
236
|
+
uri = URI.parse(amqp_url)
|
237
|
+
{
|
238
|
+
:vhost => uri.path,
|
239
|
+
:host => uri.host,
|
240
|
+
:user => uri.user,
|
241
|
+
:port => (uri.port || 5672),
|
242
|
+
:pass => uri.password
|
243
|
+
}
|
244
|
+
rescue Object => e
|
245
|
+
raise "invalid AMQP_URL: #{uri.inspect} (#{e})"
|
246
|
+
end
|
247
|
+
|
248
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Stooge
|
2
|
+
class Handler
|
3
|
+
|
4
|
+
attr_accessor :queue_name, :queue_options, :block
|
5
|
+
|
6
|
+
#
|
7
|
+
# Create a new handler object.
|
8
|
+
#
|
9
|
+
# @param [String] queue the name of the queue that this handler will pick
|
10
|
+
# jobs from.
|
11
|
+
# @param [Hash] options handler options.
|
12
|
+
# @option options [Hash] :queue_options Options to use when creating the
|
13
|
+
# queue.
|
14
|
+
#
|
15
|
+
def initialize(queue, options = {})
|
16
|
+
@queue_name = queue
|
17
|
+
@queue_options = options[:queue_options] || {}
|
18
|
+
@options = options
|
19
|
+
@block = lambda {}
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Start subscribing to the queue that this handler corresponds to. When
|
24
|
+
# a message arive; parse it and call the handler block with the data.
|
25
|
+
#
|
26
|
+
# @param [AMQP::Channel] channel an open AMQP channel
|
27
|
+
#
|
28
|
+
def start(channel)
|
29
|
+
Stooge.log "starting handler for #{@queue_name}"
|
30
|
+
channel.queue(@queue_name, @queue_options) do |queue|
|
31
|
+
queue.subscribe(:ack => true) do |metadata, payload|
|
32
|
+
Stooge.log "recv: #{@queue_name}"
|
33
|
+
begin
|
34
|
+
case metadata.content_type
|
35
|
+
when 'application/json'
|
36
|
+
args = MultiJson.decode(payload)
|
37
|
+
else
|
38
|
+
args = payload
|
39
|
+
end
|
40
|
+
@block.call(args, metadata.headers)
|
41
|
+
rescue Object => e
|
42
|
+
if Stooge.error_handler
|
43
|
+
Stooge.error_handler.call(e,self,payload,metadata)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
metadata.ack
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Stooge
|
2
|
+
module WorkQueue
|
3
|
+
|
4
|
+
#
|
5
|
+
# Push a job onto a named queue.
|
6
|
+
#
|
7
|
+
# Example:
|
8
|
+
#
|
9
|
+
# Stooge.enqueue('example.work')
|
10
|
+
#
|
11
|
+
# @param [String] queue_name The name of a work queue or an array of
|
12
|
+
# names that the job will be sent through in sequential order (a
|
13
|
+
# workflow).
|
14
|
+
# @param [Object] data The data to send as input to the job. Needs to be
|
15
|
+
# JSON serializable.
|
16
|
+
# @param [Hash] headers AMQP headers to include in the job that gets
|
17
|
+
# pushed. Needs to be a hash with key/value pairs.
|
18
|
+
#
|
19
|
+
def enqueue(queue_name, data, headers = {})
|
20
|
+
EM::Synchrony.sync(aenqueue(queue_name, data, headers))
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# Asynchrounous version of enqueue. Yields when the job has been put onto
|
25
|
+
# the queue, if a block is given.
|
26
|
+
#
|
27
|
+
# @param [String] queue_name The name of a work queue or an array of
|
28
|
+
# names that the job will be sent through in sequential order (a
|
29
|
+
# workflow).
|
30
|
+
# @param [Object] data The data to send as input to the job. Needs to be
|
31
|
+
# JSON serializable.
|
32
|
+
# @param [Hash] headers AMQP headers to include in the job that gets
|
33
|
+
# pushed. Needs to be a hash with key/value pairs.
|
34
|
+
#
|
35
|
+
# @return [EM::DefaultDeferrable] Returns an EM::DefaultDeferrable object.
|
36
|
+
#
|
37
|
+
def aenqueue(queue_name, data, headers = {})
|
38
|
+
deferrable = EM::DefaultDeferrable.new
|
39
|
+
with_channel do |channel|
|
40
|
+
options = {
|
41
|
+
:routing_key => queue_name,
|
42
|
+
:mandatory => true,
|
43
|
+
:content_type => 'application/json',
|
44
|
+
:headers => headers
|
45
|
+
}
|
46
|
+
channel.default_exchange.publish(MultiJson.encode(data), options) do
|
47
|
+
Stooge.log("enqueue: #{queue_name}(#{data})")
|
48
|
+
yield if block_given?
|
49
|
+
deferrable.set_deferred_status :succeeded
|
50
|
+
end
|
51
|
+
end
|
52
|
+
deferrable
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# Creates a job handler for a named queue.
|
57
|
+
#
|
58
|
+
# Example:
|
59
|
+
#
|
60
|
+
# Stooge.job('example.work') do |args,headers|
|
61
|
+
# # Do the work here...
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
# @param [String] queue The name of the work queue.
|
65
|
+
# @param [Proc] blk a {::Proc} that processes the jobs.
|
66
|
+
#
|
67
|
+
def job(queue, &blk)
|
68
|
+
handler = Stooge::Handler.new(queue, :queue_options => { :durable => true })
|
69
|
+
handler.block = blk
|
70
|
+
add_handler(handler)
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Stooge
|
2
|
+
class Worker
|
3
|
+
|
4
|
+
#
|
5
|
+
# Start the Stooge worker that processes jobs.
|
6
|
+
#
|
7
|
+
def self.run!
|
8
|
+
Stooge.log "Starting stooge"
|
9
|
+
|
10
|
+
Signal.trap('INT') { Stooge.stop! }
|
11
|
+
Signal.trap('TERM'){ Stooge.stop! }
|
12
|
+
|
13
|
+
Stooge.start!
|
14
|
+
end
|
15
|
+
|
16
|
+
#
|
17
|
+
# Should the Stooge worker be started?
|
18
|
+
#
|
19
|
+
# @return [Boolean] true or false
|
20
|
+
#
|
21
|
+
def self.run?
|
22
|
+
Stooge.handlers? &&
|
23
|
+
File.expand_path($0) == File.expand_path(app_file)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
CALLERS_TO_IGNORE = [
|
29
|
+
/\/stooge(\/worker)?\.rb$/,
|
30
|
+
/rubygems\/custom_require\.rb$/,
|
31
|
+
/bundler(\/runtime)?\.rb/,
|
32
|
+
/<internal:/
|
33
|
+
]
|
34
|
+
|
35
|
+
CALLERS_TO_IGNORE.concat(RUBY_IGNORE_CALLERS) if defined?(RUBY_IGNORE_CALLERS)
|
36
|
+
|
37
|
+
def self.caller_files
|
38
|
+
cleaned_caller(1).flatten
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.caller_locations
|
42
|
+
cleaned_caller 2
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.cleaned_caller(keep = 3)
|
46
|
+
caller(1).
|
47
|
+
map { |line| line.split(/:(?=\d|in )/, 3)[0,keep] }.
|
48
|
+
reject { |file, *_| CALLERS_TO_IGNORE.any? { |pattern| file =~ pattern } }
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.app_file
|
52
|
+
caller_files.first || $0
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Starte the worker at exit, if appropriate.
|
59
|
+
#
|
60
|
+
at_exit { Worker.run! if $!.nil? && Worker.run? }
|
61
|
+
end
|
data/spec/stooge_spec.rb
ADDED
data/stooge.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "stooge/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "stooge"
|
7
|
+
s.version = Stooge::VERSION
|
8
|
+
s.authors = ["Niklas Holmgren"]
|
9
|
+
s.email = ["niklas@sutajio.se"]
|
10
|
+
s.homepage = "https://github.com/sutajio/stooge"
|
11
|
+
s.summary = %q{Super advanced job queue over AMQP}
|
12
|
+
s.description = %q{Super advanced job queue over AMQP}
|
13
|
+
|
14
|
+
s.rubyforge_project = "stooge"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_dependency 'amqp'
|
22
|
+
s.add_dependency 'em-synchrony'
|
23
|
+
s.add_dependency 'multi_json'
|
24
|
+
s.add_development_dependency 'rspec'
|
25
|
+
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: stooge
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Niklas Holmgren
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-03-14 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: amqp
|
16
|
+
requirement: &70330131821100 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70330131821100
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: em-synchrony
|
27
|
+
requirement: &70330131820660 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70330131820660
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: multi_json
|
38
|
+
requirement: &70330131820200 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70330131820200
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rspec
|
49
|
+
requirement: &70330131819740 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70330131819740
|
58
|
+
description: Super advanced job queue over AMQP
|
59
|
+
email:
|
60
|
+
- niklas@sutajio.se
|
61
|
+
executables: []
|
62
|
+
extensions: []
|
63
|
+
extra_rdoc_files: []
|
64
|
+
files:
|
65
|
+
- .gitignore
|
66
|
+
- .rvmrc
|
67
|
+
- Gemfile
|
68
|
+
- HISTORY.md
|
69
|
+
- LICENSE
|
70
|
+
- README.md
|
71
|
+
- Rakefile
|
72
|
+
- lib/stooge.rb
|
73
|
+
- lib/stooge/handler.rb
|
74
|
+
- lib/stooge/version.rb
|
75
|
+
- lib/stooge/work_queue.rb
|
76
|
+
- lib/stooge/worker.rb
|
77
|
+
- spec/stooge_spec.rb
|
78
|
+
- stooge.gemspec
|
79
|
+
homepage: https://github.com/sutajio/stooge
|
80
|
+
licenses: []
|
81
|
+
post_install_message:
|
82
|
+
rdoc_options: []
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ! '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
+
none: false
|
93
|
+
requirements:
|
94
|
+
- - ! '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
requirements: []
|
98
|
+
rubyforge_project: stooge
|
99
|
+
rubygems_version: 1.8.17
|
100
|
+
signing_key:
|
101
|
+
specification_version: 3
|
102
|
+
summary: Super advanced job queue over AMQP
|
103
|
+
test_files:
|
104
|
+
- spec/stooge_spec.rb
|