resque-bus 0.2.4 → 0.2.5
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/lib/resque-bus.rb +233 -229
- data/lib/resque_bus/application.rb +9 -4
- data/lib/resque_bus/dispatch.rb +4 -2
- data/lib/resque_bus/driver.rb +18 -16
- data/lib/resque_bus/local.rb +21 -19
- data/lib/resque_bus/publisher.rb +6 -3
- data/lib/resque_bus/rider.rb +41 -39
- data/lib/resque_bus/subscription.rb +28 -25
- data/lib/resque_bus/subscription_list.rb +12 -8
- data/lib/resque_bus/task_manager.rb +2 -0
- data/lib/resque_bus/version.rb +1 -1
- data/spec/spec_helper.rb +1 -3
- metadata +2 -2
data/lib/resque-bus.rb
CHANGED
@@ -1,250 +1,254 @@
|
|
1
|
+
require "resque_bus/version"
|
2
|
+
|
1
3
|
require 'redis/namespace'
|
2
4
|
require 'resque'
|
3
5
|
|
4
|
-
require "resque_bus/version"
|
5
|
-
require 'resque_bus/util'
|
6
|
-
require 'resque_bus/matcher'
|
7
|
-
require 'resque_bus/subscription'
|
8
|
-
require 'resque_bus/subscription_list'
|
9
|
-
require 'resque_bus/subscriber'
|
10
|
-
require 'resque_bus/application'
|
11
|
-
require 'resque_bus/publisher'
|
12
|
-
require 'resque_bus/driver'
|
13
|
-
require 'resque_bus/local'
|
14
|
-
require 'resque_bus/rider'
|
15
|
-
require 'resque_bus/dispatch'
|
16
|
-
require 'resque_bus/task_manager'
|
17
6
|
|
18
7
|
module ResqueBus
|
19
|
-
extend self
|
20
|
-
|
21
|
-
def default_app_key=val
|
22
|
-
@default_app_key = Application.normalize(val)
|
23
|
-
end
|
24
|
-
|
25
|
-
def default_app_key
|
26
|
-
@default_app_key
|
27
|
-
end
|
28
8
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
9
|
+
autoload :Application, 'resque_bus/application'
|
10
|
+
autoload :Dispatch, 'resque_bus/dispatch'
|
11
|
+
autoload :Driver, 'resque_bus/driver'
|
12
|
+
autoload :Local, 'resque_bus/local'
|
13
|
+
autoload :Matcher, 'resque_bus/matcher'
|
14
|
+
autoload :Publisher, 'resque_bus/publisher'
|
15
|
+
autoload :Rider, 'resque_bus/rider'
|
16
|
+
autoload :Subscriber, 'resque_bus/subscriber'
|
17
|
+
autoload :Subscription, 'resque_bus/subscription'
|
18
|
+
autoload :SubscriptionList, 'resque_bus/subscription_list'
|
19
|
+
autoload :TaskManager, 'resque_bus/task_manager'
|
20
|
+
autoload :Util, 'resque_bus/util'
|
36
21
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
@dispatchers ||= {}
|
55
|
-
@dispatchers[app_key] ||= Dispatch.new(app_key)
|
56
|
-
end
|
57
|
-
|
58
|
-
def dispatcher_execute(app_key, key, attributes)
|
59
|
-
@dispatchers ||= {}
|
60
|
-
dispatcher = @dispatchers[app_key]
|
61
|
-
dispatcher.execute(key, attributes) if dispatcher
|
62
|
-
end
|
22
|
+
class << self
|
23
|
+
|
24
|
+
def default_app_key=val
|
25
|
+
@default_app_key = Application.normalize(val)
|
26
|
+
end
|
27
|
+
|
28
|
+
def default_app_key
|
29
|
+
@default_app_key
|
30
|
+
end
|
31
|
+
|
32
|
+
def default_queue=val
|
33
|
+
@default_queue = val
|
34
|
+
end
|
35
|
+
|
36
|
+
def default_queue
|
37
|
+
@default_queue
|
38
|
+
end
|
63
39
|
|
64
|
-
|
65
|
-
|
66
|
-
|
40
|
+
def hostname
|
41
|
+
@hostname ||= `hostname 2>&1`.strip.sub(/.local/,'')
|
42
|
+
end
|
43
|
+
|
44
|
+
def dispatch(app_key=nil, &block)
|
45
|
+
dispatcher = dispatcher_by_key(app_key)
|
46
|
+
dispatcher.instance_eval(&block)
|
47
|
+
dispatcher
|
48
|
+
end
|
49
|
+
|
50
|
+
def dispatchers
|
51
|
+
@dispatchers ||= {}
|
52
|
+
@dispatchers.values
|
53
|
+
end
|
54
|
+
|
55
|
+
def dispatcher_by_key(app_key)
|
56
|
+
app_key = Application.normalize(app_key || default_app_key)
|
57
|
+
@dispatchers ||= {}
|
58
|
+
@dispatchers[app_key] ||= Dispatch.new(app_key)
|
59
|
+
end
|
60
|
+
|
61
|
+
def dispatcher_execute(app_key, key, attributes)
|
62
|
+
@dispatchers ||= {}
|
63
|
+
dispatcher = @dispatchers[app_key]
|
64
|
+
dispatcher.execute(key, attributes) if dispatcher
|
65
|
+
end
|
67
66
|
|
68
|
-
|
69
|
-
|
70
|
-
|
67
|
+
def local_mode=value
|
68
|
+
@local_mode = value
|
69
|
+
end
|
70
|
+
|
71
|
+
def local_mode
|
72
|
+
@local_mode
|
73
|
+
end
|
74
|
+
|
75
|
+
# Accepts:
|
76
|
+
# 1. A 'hostname:port' String
|
77
|
+
# 2. A 'hostname:port:db' String (to select the Redis db)
|
78
|
+
# 3. A 'hostname:port/namespace' String (to set the Redis namespace)
|
79
|
+
# 4. A Redis URL String 'redis://host:port'
|
80
|
+
# 5. An instance of `Redis`, `Redis::Client`, `Redis::DistRedis`,
|
81
|
+
# or `Redis::Namespace`.
|
82
|
+
def redis=(server)
|
83
|
+
case server
|
84
|
+
when String
|
85
|
+
if server =~ /redis\:\/\//
|
86
|
+
redis = Redis.connect(:url => server, :thread_safe => true)
|
87
|
+
else
|
88
|
+
server, namespace = server.split('/', 2)
|
89
|
+
host, port, db = server.split(':')
|
90
|
+
redis = Redis.new(:host => host, :port => port,
|
91
|
+
:thread_safe => true, :db => db)
|
92
|
+
end
|
93
|
+
namespace ||= default_namespace
|
71
94
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
# 3. A 'hostname:port/namespace' String (to set the Redis namespace)
|
76
|
-
# 4. A Redis URL String 'redis://host:port'
|
77
|
-
# 5. An instance of `Redis`, `Redis::Client`, `Redis::DistRedis`,
|
78
|
-
# or `Redis::Namespace`.
|
79
|
-
def redis=(server)
|
80
|
-
case server
|
81
|
-
when String
|
82
|
-
if server =~ /redis\:\/\//
|
83
|
-
redis = Redis.connect(:url => server, :thread_safe => true)
|
95
|
+
@redis = Redis::Namespace.new(namespace, :redis => redis)
|
96
|
+
when Redis::Namespace
|
97
|
+
@redis = server
|
84
98
|
else
|
85
|
-
|
86
|
-
host, port, db = server.split(':')
|
87
|
-
redis = Redis.new(:host => host, :port => port,
|
88
|
-
:thread_safe => true, :db => db)
|
99
|
+
@redis = Redis::Namespace.new(default_namespace, :redis => server)
|
89
100
|
end
|
90
|
-
namespace ||= default_namespace
|
91
|
-
|
92
|
-
@redis = Redis::Namespace.new(namespace, :redis => redis)
|
93
|
-
when Redis::Namespace
|
94
|
-
@redis = server
|
95
|
-
else
|
96
|
-
@redis = Redis::Namespace.new(default_namespace, :redis => server)
|
97
101
|
end
|
98
|
-
end
|
99
102
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
end
|
109
|
-
|
110
|
-
def original_redis=(server)
|
111
|
-
@original_redis = server
|
112
|
-
end
|
113
|
-
def original_redis
|
114
|
-
@original_redis
|
115
|
-
end
|
116
|
-
|
117
|
-
def publish_metadata(event_type, attributes={})
|
118
|
-
# TODO: "bus_app_key" => application.app_key ?
|
119
|
-
bus_attr = {"bus_published_at" => Time.now.to_i, "created_at" => Time.now.to_i, "bus_event_type" => event_type}
|
120
|
-
bus_attr["bus_id"] ||= "#{Time.now.to_i}-#{generate_uuid}"
|
121
|
-
bus_attr["bus_app_hostname"] = hostname
|
122
|
-
bus_attr.merge(attributes || {})
|
123
|
-
end
|
124
|
-
|
125
|
-
def generate_uuid
|
126
|
-
require 'securerandom' unless defined?(SecureRandom)
|
127
|
-
return SecureRandom.uuid
|
128
|
-
|
129
|
-
rescue Exception => e
|
130
|
-
# secure random not there
|
131
|
-
# big random number a few times
|
132
|
-
n_bytes = [42].pack('i').size
|
133
|
-
n_bits = n_bytes * 8
|
134
|
-
max = 2 ** (n_bits - 2) - 1
|
135
|
-
return "#{rand(max)}-#{rand(max)}-#{rand(max)}"
|
136
|
-
end
|
137
|
-
|
138
|
-
def publish(event_type, attributes = {})
|
139
|
-
to_publish = publish_metadata(event_type, attributes)
|
140
|
-
ResqueBus.log_application("Event published: #{event_type} #{to_publish.inspect}")
|
141
|
-
if local_mode
|
142
|
-
ResqueBus::Local.perform(to_publish)
|
143
|
-
else
|
144
|
-
enqueue_to(incoming_queue, Driver, to_publish)
|
103
|
+
# Returns the current Redis connection. If none has been created, will
|
104
|
+
# create a new one from the Reqsue one (with a different namespace)
|
105
|
+
def redis
|
106
|
+
return @redis if @redis
|
107
|
+
copy = Resque.redis.clone
|
108
|
+
copy.namespace = default_namespace
|
109
|
+
self.redis = copy
|
110
|
+
self.redis
|
145
111
|
end
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
to_publish = publish_metadata(event_type, attributes)
|
150
|
-
to_publish["bus_delayed_until"] ||= timestamp_or_epoch.to_i
|
151
|
-
to_publish.delete("bus_published_at") unless attributes["bus_published_at"] # will be put on when it actually does it
|
152
|
-
|
153
|
-
ResqueBus.log_application("Event published:#{event_type} #{to_publish.inspect} publish_at: #{timestamp_or_epoch.to_i}")
|
154
|
-
item = delayed_job_to_hash_with_queue(incoming_queue, Publisher, [event_type, to_publish])
|
155
|
-
delayed_push(timestamp_or_epoch, item)
|
156
|
-
end
|
157
|
-
|
158
|
-
def enqueue_to(queue, klass, *args)
|
159
|
-
push(queue, :class => klass.to_s, :args => args)
|
160
|
-
end
|
161
|
-
|
162
|
-
def logger
|
163
|
-
@logger
|
164
|
-
end
|
165
|
-
|
166
|
-
def logger=val
|
167
|
-
@logger = val
|
168
|
-
end
|
169
|
-
|
170
|
-
def log_application(message)
|
171
|
-
if logger
|
172
|
-
time = Time.now.strftime('%H:%M:%S %Y-%m-%d')
|
173
|
-
logger.info("** [#{time}] #$$: ResqueBus #{message}")
|
112
|
+
|
113
|
+
def original_redis=(server)
|
114
|
+
@original_redis = server
|
174
115
|
end
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
116
|
+
def original_redis
|
117
|
+
@original_redis
|
118
|
+
end
|
119
|
+
|
120
|
+
def publish_metadata(event_type, attributes={})
|
121
|
+
# TODO: "bus_app_key" => application.app_key ?
|
122
|
+
bus_attr = {"bus_published_at" => Time.now.to_i, "created_at" => Time.now.to_i, "bus_event_type" => event_type}
|
123
|
+
bus_attr["bus_id"] ||= "#{Time.now.to_i}-#{generate_uuid}"
|
124
|
+
bus_attr["bus_app_hostname"] = hostname
|
125
|
+
bus_attr.merge(attributes || {})
|
126
|
+
end
|
127
|
+
|
128
|
+
def generate_uuid
|
129
|
+
require 'securerandom' unless defined?(SecureRandom)
|
130
|
+
return SecureRandom.uuid
|
131
|
+
|
132
|
+
rescue Exception => e
|
133
|
+
# secure random not there
|
134
|
+
# big random number a few times
|
135
|
+
n_bytes = [42].pack('i').size
|
136
|
+
n_bits = n_bytes * 8
|
137
|
+
max = 2 ** (n_bits - 2) - 1
|
138
|
+
return "#{rand(max)}-#{rand(max)}-#{rand(max)}"
|
139
|
+
end
|
140
|
+
|
141
|
+
def publish(event_type, attributes = {})
|
142
|
+
to_publish = publish_metadata(event_type, attributes)
|
143
|
+
ResqueBus.log_application("Event published: #{event_type} #{to_publish.inspect}")
|
144
|
+
if local_mode
|
145
|
+
ResqueBus::Local.perform(to_publish)
|
146
|
+
else
|
147
|
+
enqueue_to(incoming_queue, Driver, to_publish)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def publish_at(timestamp_or_epoch, event_type, attributes = {})
|
152
|
+
to_publish = publish_metadata(event_type, attributes)
|
153
|
+
to_publish["bus_delayed_until"] ||= timestamp_or_epoch.to_i
|
154
|
+
to_publish.delete("bus_published_at") unless attributes["bus_published_at"] # will be put on when it actually does it
|
155
|
+
|
156
|
+
ResqueBus.log_application("Event published:#{event_type} #{to_publish.inspect} publish_at: #{timestamp_or_epoch.to_i}")
|
157
|
+
item = delayed_job_to_hash_with_queue(incoming_queue, Publisher, [event_type, to_publish])
|
158
|
+
delayed_push(timestamp_or_epoch, item)
|
159
|
+
end
|
160
|
+
|
161
|
+
def enqueue_to(queue, klass, *args)
|
162
|
+
push(queue, :class => klass.to_s, :args => args)
|
163
|
+
end
|
164
|
+
|
165
|
+
def logger
|
166
|
+
@logger
|
167
|
+
end
|
168
|
+
|
169
|
+
def logger=val
|
170
|
+
@logger = val
|
171
|
+
end
|
172
|
+
|
173
|
+
def log_application(message)
|
174
|
+
if logger
|
175
|
+
time = Time.now.strftime('%H:%M:%S %Y-%m-%d')
|
176
|
+
logger.info("** [#{time}] #$$: ResqueBus #{message}")
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def log_worker(message)
|
181
|
+
if ENV['LOGGING'] || ENV['VERBOSE'] || ENV['VVERBOSE']
|
182
|
+
time = Time.now.strftime('%H:%M:%S %Y-%m-%d')
|
183
|
+
puts "** [#{time}] #$$: #{message}"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
protected
|
188
|
+
|
189
|
+
def reset
|
190
|
+
# used by tests
|
191
|
+
@redis = nil # clear instance of redis
|
192
|
+
@dispatcher = nil
|
193
|
+
@default_app_key = nil
|
194
|
+
@default_queue = nil
|
195
|
+
end
|
196
|
+
|
197
|
+
def incoming_queue
|
198
|
+
"resquebus_incoming"
|
181
199
|
end
|
182
|
-
end
|
183
|
-
|
184
|
-
protected
|
185
|
-
|
186
|
-
def reset
|
187
|
-
# used by tests
|
188
|
-
@redis = nil # clear instance of redis
|
189
|
-
@dispatcher = nil
|
190
|
-
@default_app_key = nil
|
191
|
-
@default_queue = nil
|
192
|
-
end
|
193
|
-
|
194
|
-
def incoming_queue
|
195
|
-
"resquebus_incoming"
|
196
|
-
end
|
197
200
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
201
|
+
def default_namespace
|
202
|
+
# It might play better on the same server, but overall life is more complicated
|
203
|
+
:resque
|
204
|
+
end
|
205
|
+
|
206
|
+
## From Resque, but using a (possibly) different instance of Redis
|
207
|
+
|
208
|
+
# Pushes a job onto a queue. Queue name should be a string and the
|
209
|
+
# item should be any JSON-able Ruby object.
|
210
|
+
#
|
211
|
+
# Resque works generally expect the `item` to be a hash with the following
|
212
|
+
# keys:
|
213
|
+
#
|
214
|
+
# class - The String name of the job to run.
|
215
|
+
# args - An Array of arguments to pass the job. Usually passed
|
216
|
+
# via `class.to_class.perform(*args)`.
|
217
|
+
#
|
218
|
+
# Example
|
219
|
+
#
|
220
|
+
# Resque.push('archive', :class => 'Archive', :args => [ 35, 'tar' ])
|
221
|
+
#
|
222
|
+
# Returns nothing
|
223
|
+
def push(queue, item)
|
224
|
+
watch_queue(queue)
|
225
|
+
redis.rpush "queue:#{queue}", Resque.encode(item)
|
226
|
+
end
|
227
|
+
|
228
|
+
# Used internally to keep track of which queues we've created.
|
229
|
+
# Don't call this directly.
|
230
|
+
def watch_queue(queue)
|
231
|
+
redis.sadd(:queues, queue.to_s)
|
232
|
+
end
|
233
|
+
|
234
|
+
### From Resque Scheduler
|
235
|
+
# Used internally to stuff the item into the schedule sorted list.
|
236
|
+
# +timestamp+ can be either in seconds or a datetime object
|
237
|
+
# Insertion if O(log(n)).
|
238
|
+
# Returns true if it's the first job to be scheduled at that time, else false
|
239
|
+
def delayed_push(timestamp, item)
|
240
|
+
# First add this item to the list for this timestamp
|
241
|
+
redis.rpush("delayed:#{timestamp.to_i}", Resque.encode(item))
|
239
242
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
243
|
+
# Now, add this timestamp to the zsets. The score and the value are
|
244
|
+
# the same since we'll be querying by timestamp, and we don't have
|
245
|
+
# anything else to store.
|
246
|
+
redis.zadd :delayed_queue_schedule, timestamp.to_i, timestamp.to_i
|
247
|
+
end
|
248
|
+
|
249
|
+
def delayed_job_to_hash_with_queue(queue, klass, args)
|
250
|
+
{:class => klass.to_s, :args => args, :queue => queue}
|
251
|
+
end
|
248
252
|
end
|
249
253
|
|
250
|
-
end
|
254
|
+
end
|
@@ -1,11 +1,16 @@
|
|
1
1
|
module ResqueBus
|
2
2
|
class Application
|
3
|
-
|
3
|
+
|
4
|
+
class << self
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
def all
|
7
|
+
# note the names arent the same as we started with
|
8
|
+
ResqueBus.redis.smembers(app_list_key).collect{ |val| new(val) }
|
9
|
+
end
|
8
10
|
end
|
11
|
+
|
12
|
+
attr_reader :app_key, :redis_key
|
13
|
+
|
9
14
|
|
10
15
|
def initialize(app_key)
|
11
16
|
@app_key = self.class.normalize(app_key)
|
data/lib/resque_bus/dispatch.rb
CHANGED
@@ -2,7 +2,9 @@
|
|
2
2
|
|
3
3
|
module ResqueBus
|
4
4
|
class Dispatch
|
5
|
+
|
5
6
|
attr_reader :app_key, :subscriptions
|
7
|
+
|
6
8
|
def initialize(app_key)
|
7
9
|
@app_key = Application.normalize(app_key)
|
8
10
|
@subscriptions = SubscriptionList.new
|
@@ -18,9 +20,9 @@ module ResqueBus
|
|
18
20
|
|
19
21
|
# allows definitions of other queues
|
20
22
|
def method_missing(method_name, *args, &block)
|
21
|
-
if args.size == 1
|
23
|
+
if args.size == 1 && block
|
22
24
|
dispatch_event(method_name, args[0], nil, block)
|
23
|
-
elsif args.size == 2
|
25
|
+
elsif args.size == 2 && block
|
24
26
|
dispatch_event(method_name, args[0], args[1], block)
|
25
27
|
else
|
26
28
|
super
|
data/lib/resque_bus/driver.rb
CHANGED
@@ -2,27 +2,29 @@ module ResqueBus
|
|
2
2
|
# fans out an event to multiple queues
|
3
3
|
class Driver
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
class << self
|
6
|
+
def subscription_matches(attributes)
|
7
|
+
out = []
|
8
|
+
Application.all.each do |app|
|
9
|
+
subs = app.subscription_matches(attributes)
|
10
|
+
out.concat(subs)
|
11
|
+
end
|
12
|
+
out
|
10
13
|
end
|
11
|
-
out
|
12
|
-
end
|
13
14
|
|
14
|
-
|
15
|
-
|
15
|
+
def perform(attributes={})
|
16
|
+
raise "No attribiutes passed" if attributes.empty?
|
16
17
|
|
17
|
-
|
18
|
+
ResqueBus.log_worker("Driver running: #{attributes.inspect}")
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
subscription_matches(attributes).each do |sub|
|
21
|
+
ResqueBus.log_worker(" ...sending to #{sub.queue_name} queue with class #{sub.class_name} for app #{sub.app_key} because of subscription: #{sub.key}")
|
22
|
+
|
23
|
+
bus_attr = {"bus_driven_at" => Time.now.to_i, "bus_rider_queue" => sub.queue_name, "bus_rider_app_key" => sub.app_key, "bus_rider_sub_key" => sub.key, "bus_rider_class_name" => sub.class_name}
|
24
|
+
ResqueBus.enqueue_to(sub.queue_name, sub.class_name, bus_attr.merge(attributes || {}))
|
25
|
+
end
|
24
26
|
end
|
25
27
|
end
|
26
28
|
|
27
29
|
end
|
28
|
-
end
|
30
|
+
end
|
data/lib/resque_bus/local.rb
CHANGED
@@ -2,30 +2,32 @@ module ResqueBus
|
|
2
2
|
# only process local queues
|
3
3
|
class Local
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
class << self
|
6
|
+
def perform(attributes = {})
|
7
|
+
ResqueBus.log_worker("Local running: #{attributes.inspect}")
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
9
|
+
# looking for subscriptions, not queues
|
10
|
+
subscription_matches(attributes).each do |sub|
|
11
|
+
bus_attr = {"bus_driven_at" => Time.now.to_i, "bus_rider_queue" => sub.queue_name, "bus_rider_app_key" => sub.app_key, "bus_rider_sub_key" => sub.key, "bus_rider_class_name" => sub.class_name}
|
12
|
+
to_publish = bus_attr.merge(attributes || {})
|
13
|
+
if ResqueBus.local_mode == :standalone
|
14
|
+
ResqueBus.enqueue_to(sub.queue_name, sub.class_name, bus_attr.merge(attributes || {}))
|
15
|
+
# defaults to inline mode
|
16
|
+
else ResqueBus.local_mode == :inline
|
17
|
+
sub.execute!(to_publish)
|
18
|
+
end
|
17
19
|
end
|
18
20
|
end
|
19
|
-
end
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
22
|
+
# looking directly at subscriptions loaded into dispatcher
|
23
|
+
# so we don't need redis server up
|
24
|
+
def self.subscription_matches(attributes)
|
25
|
+
out = []
|
26
|
+
ResqueBus.dispatchers.each do |dispatcher|
|
27
|
+
out.concat(dispatcher.subscription_matches(attributes))
|
28
|
+
end
|
29
|
+
out
|
27
30
|
end
|
28
|
-
out
|
29
31
|
end
|
30
32
|
|
31
33
|
end
|
data/lib/resque_bus/publisher.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
module ResqueBus
|
2
2
|
# publishes on a delay
|
3
3
|
class Publisher
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
class << self
|
5
|
+
def perform(event_type, attributes = {})
|
6
|
+
ResqueBus.log_worker("Publisher running: #{event_type} - #{attributes.inspect}")
|
7
|
+
ResqueBus.publish(event_type, attributes)
|
8
|
+
end
|
7
9
|
end
|
10
|
+
|
8
11
|
end
|
9
12
|
end
|
data/lib/resque_bus/rider.rb
CHANGED
@@ -5,48 +5,50 @@ module ResqueBus
|
|
5
5
|
class Rider
|
6
6
|
extend Resque::Plugins::ExponentialBackoff
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
class << self
|
9
|
+
def perform(attributes = {})
|
10
|
+
sub_key = attributes["bus_rider_sub_key"]
|
11
|
+
app_key = attributes["bus_rider_app_key"]
|
12
|
+
raise "No application key passed" if app_key.to_s == ""
|
13
|
+
raise "No subcription key passed" if sub_key.to_s == ""
|
14
|
+
|
15
|
+
attributes ||= {}
|
16
|
+
|
17
|
+
ResqueBus.log_worker("Rider received: #{app_key} #{sub_key} #{attributes.inspect}")
|
18
|
+
|
19
|
+
# attributes that should be available
|
20
|
+
# attributes["bus_event_type"]
|
21
|
+
# attributes["bus_app_key"]
|
22
|
+
# attributes["bus_published_at"]
|
23
|
+
# attributes["bus_driven_at"]
|
24
|
+
|
25
|
+
# allow the real Reqsue to be used inside the callback while in a worker
|
26
|
+
Resque.redis = ResqueBus.original_redis if ResqueBus.original_redis
|
27
|
+
|
28
|
+
# (now running with the real app that subscribed)
|
29
|
+
ResqueBus.dispatcher_execute(app_key, sub_key, attributes.merge("bus_executed_at" => Time.now.to_i))
|
30
|
+
ensure
|
31
|
+
# put this back if running in the thread
|
32
|
+
Resque.redis = ResqueBus.redis if ResqueBus.original_redis
|
33
|
+
end
|
13
34
|
|
14
|
-
|
35
|
+
# @failure_hooks_already_ran on https://github.com/defunkt/resque/tree/1-x-stable
|
36
|
+
# to prevent running twice
|
37
|
+
def queue
|
38
|
+
@my_queue
|
39
|
+
end
|
15
40
|
|
16
|
-
|
41
|
+
def on_failure_aaa(exception, *args)
|
42
|
+
# note: sorted alphabetically
|
43
|
+
# queue needs to be set for rety to work (know what queue in Requeue.class_to_queue)
|
44
|
+
@my_queue = args[0]["bus_rider_queue"]
|
45
|
+
end
|
17
46
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
# allow the real Reqsue to be used inside the callback while in a worker
|
25
|
-
Resque.redis = ResqueBus.original_redis if ResqueBus.original_redis
|
26
|
-
|
27
|
-
# (now running with the real app that subscribed)
|
28
|
-
ResqueBus.dispatcher_execute(app_key, sub_key, attributes.merge("bus_executed_at" => Time.now.to_i))
|
29
|
-
ensure
|
30
|
-
# put this back if running in the thread
|
31
|
-
Resque.redis = ResqueBus.redis if ResqueBus.original_redis
|
32
|
-
end
|
33
|
-
|
34
|
-
# @failure_hooks_already_ran on https://github.com/defunkt/resque/tree/1-x-stable
|
35
|
-
# to prevent running twice
|
36
|
-
def self.queue
|
37
|
-
@my_queue
|
38
|
-
end
|
39
|
-
|
40
|
-
def self.on_failure_aaa(exception, *args)
|
41
|
-
# note: sorted alphabetically
|
42
|
-
# queue needs to be set for rety to work (know what queue in Requeue.class_to_queue)
|
43
|
-
@my_queue = args[0]["bus_rider_queue"]
|
44
|
-
end
|
45
|
-
|
46
|
-
def self.on_failure_zzz(exception, *args)
|
47
|
-
# note: sorted alphabetically
|
48
|
-
@my_queue = nil
|
47
|
+
def on_failure_zzz(exception, *args)
|
48
|
+
# note: sorted alphabetically
|
49
|
+
@my_queue = nil
|
50
|
+
end
|
51
|
+
|
49
52
|
end
|
50
|
-
|
51
53
|
end
|
52
54
|
end
|
@@ -1,29 +1,28 @@
|
|
1
1
|
module ResqueBus
|
2
2
|
class Subscription
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
out["matcher"] = matcher.to_redis
|
22
|
-
out
|
3
|
+
|
4
|
+
class << self
|
5
|
+
def register(queue, key, class_name, matcher, block)
|
6
|
+
Subscription.new(queue, key, class_name, matcher, block)
|
7
|
+
end
|
8
|
+
|
9
|
+
def from_redis(hash)
|
10
|
+
queue_name = hash["queue_name"].to_s
|
11
|
+
key = hash["key"].to_s
|
12
|
+
class_name = hash["class"].to_s
|
13
|
+
matcher = hash["matcher"]
|
14
|
+
return nil if key.length == 0 || queue_name.length == 0
|
15
|
+
Subscription.new(queue_name, key, class_name, matcher, nil)
|
16
|
+
end
|
17
|
+
|
18
|
+
def normalize(val)
|
19
|
+
val.to_s.gsub(/\W/, "_").downcase
|
20
|
+
end
|
23
21
|
end
|
24
22
|
|
25
23
|
attr_reader :matcher, :executor, :queue_name, :key, :class_name
|
26
24
|
attr_accessor :app_key # dyanmically set on return from subscription_matches
|
25
|
+
|
27
26
|
def initialize(queue_name, key, class_name, filters, executor=nil)
|
28
27
|
@queue_name = self.class.normalize(queue_name)
|
29
28
|
@key = key.to_s
|
@@ -40,11 +39,15 @@ module ResqueBus
|
|
40
39
|
def matches?(attributes)
|
41
40
|
@matcher.matches?(attributes)
|
42
41
|
end
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
42
|
+
|
43
|
+
def to_redis
|
44
|
+
out = {}
|
45
|
+
out["queue_name"] = queue_name
|
46
|
+
out["key"] = key
|
47
|
+
out["class"] = class_name
|
48
|
+
out["matcher"] = matcher.to_redis
|
49
|
+
out
|
48
50
|
end
|
51
|
+
|
49
52
|
end
|
50
53
|
end
|
@@ -1,15 +1,19 @@
|
|
1
1
|
module ResqueBus
|
2
2
|
class SubscriptionList
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
|
4
|
+
class << self
|
5
|
+
def from_redis(redis_hash)
|
6
|
+
out = SubscriptionList.new
|
7
|
+
|
8
|
+
redis_hash.each do |key, value|
|
9
|
+
sub = Subscription.from_redis(value)
|
10
|
+
out.add(sub) if sub
|
11
|
+
end
|
12
|
+
|
13
|
+
out
|
9
14
|
end
|
10
|
-
out
|
11
15
|
end
|
12
|
-
|
16
|
+
|
13
17
|
def to_redis
|
14
18
|
out = {}
|
15
19
|
@subscriptions.values.each do |sub|
|
data/lib/resque_bus/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: resque-bus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-08-
|
12
|
+
date: 2013-08-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: resque
|