resque-bus 0.3.7 → 0.5.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/.gitignore +1 -0
  2. data/Gemfile +2 -2
  3. data/README.mdown +42 -64
  4. data/Rakefile +0 -1
  5. data/lib/resque-bus.rb +13 -305
  6. data/lib/resque_bus/adapter.rb +65 -0
  7. data/lib/resque_bus/compatibility/deprecated.rb +38 -0
  8. data/lib/resque_bus/compatibility/driver.rb +10 -0
  9. data/lib/resque_bus/compatibility/heartbeat.rb +10 -0
  10. data/lib/resque_bus/compatibility/publisher.rb +13 -0
  11. data/lib/resque_bus/compatibility/rider.rb +32 -0
  12. data/lib/resque_bus/compatibility/subscriber.rb +8 -0
  13. data/lib/resque_bus/compatibility/task_manager.rb +8 -0
  14. data/lib/resque_bus/server/views/bus.erb +2 -2
  15. data/lib/resque_bus/server.rb +5 -4
  16. data/lib/resque_bus/tasks.rb +46 -46
  17. data/lib/resque_bus/version.rb +2 -4
  18. data/resque-bus.gemspec +5 -10
  19. data/spec/adapter/compatibility_spec.rb +97 -0
  20. data/spec/adapter/integration_spec.rb +111 -0
  21. data/spec/adapter/publish_at_spec.rb +50 -0
  22. data/spec/adapter/retry_spec.rb +47 -0
  23. data/spec/adapter/support.rb +23 -0
  24. data/spec/adapter_spec.rb +14 -0
  25. data/spec/application_spec.rb +62 -62
  26. data/spec/config_spec.rb +83 -0
  27. data/spec/dispatch_spec.rb +6 -6
  28. data/spec/driver_spec.rb +62 -44
  29. data/spec/heartbeat_spec.rb +4 -4
  30. data/spec/integration_spec.rb +2 -2
  31. data/spec/matcher_spec.rb +29 -29
  32. data/spec/publish_spec.rb +46 -43
  33. data/spec/publisher_spec.rb +7 -0
  34. data/spec/rider_spec.rb +14 -66
  35. data/spec/spec_helper.rb +25 -25
  36. data/spec/subscriber_spec.rb +194 -176
  37. data/spec/subscription_list_spec.rb +1 -1
  38. data/spec/subscription_spec.rb +1 -1
  39. data/spec/worker_spec.rb +32 -0
  40. metadata +47 -58
  41. data/lib/resque_bus/application.rb +0 -115
  42. data/lib/resque_bus/compatibility.rb +0 -24
  43. data/lib/resque_bus/dispatch.rb +0 -61
  44. data/lib/resque_bus/driver.rb +0 -30
  45. data/lib/resque_bus/heartbeat.rb +0 -106
  46. data/lib/resque_bus/local.rb +0 -38
  47. data/lib/resque_bus/matcher.rb +0 -81
  48. data/lib/resque_bus/publisher.rb +0 -12
  49. data/lib/resque_bus/rider.rb +0 -54
  50. data/lib/resque_bus/subscriber.rb +0 -63
  51. data/lib/resque_bus/subscription.rb +0 -55
  52. data/lib/resque_bus/subscription_list.rb +0 -53
  53. data/lib/resque_bus/task_manager.rb +0 -52
  54. data/lib/resque_bus/util.rb +0 -42
  55. data/lib/tasks/resquebus.rake +0 -2
  56. data/spec/compatibility_spec.rb +0 -93
  57. data/spec/publish_at_spec.rb +0 -74
  58. data/spec/redis_spec.rb +0 -13
data/.gitignore CHANGED
@@ -2,3 +2,4 @@
2
2
  .bundle
3
3
  Gemfile.lock
4
4
  pkg/*
5
+ .DS_Store
data/Gemfile CHANGED
@@ -2,5 +2,5 @@ source "http://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem "debugger"
6
- gem "rake"
5
+ gem "rake"
6
+ # gem "queue-bus", path: "../queue-bus"
data/README.mdown CHANGED
@@ -1,6 +1,7 @@
1
1
  ## Resque Bus
2
2
 
3
- This gem uses Redis and Resque to allow simple asynchronous communication between apps.
3
+ This gem provides an adapter for Resque for use in the [queue-bus](https://github.com/queue-bus/queue-bus) system.
4
+ It uses Redis and the Resque that you are already using to allow simple asynchronous communication between apps.
4
5
 
5
6
  ### Install
6
7
 
@@ -10,35 +11,36 @@ To install, include the 'resque-bus' gem and add the following to your Rakefile:
10
11
  require "resque_bus/tasks"
11
12
  ```
12
13
 
14
+
13
15
  ### Example
14
16
 
15
17
  Application A can publish an event
16
18
 
17
19
  ```ruby
18
- # config
19
- ResqueBus.redis = "192.168.1.1:6379"
20
+ # pick an adapter
21
+ require 'resque-bus' # (or other adapter)
20
22
 
21
23
  # business logic
22
- ResqueBus.publish("user_created", "id" => 42, "first_name" => "John", "last_name" => "Smith")
24
+ QueueBus.publish("user_created", "id" => 42, "first_name" => "John", "last_name" => "Smith")
23
25
 
24
26
  # or do it later
25
- ResqueBus.publish_at(1.hour.from_now, "user_created", "id" => 42, "first_name" => "John", "last_name" => "Smith")
27
+ QueueBus.publish_at(1.hour.from_now, "user_created", "id" => 42, "first_name" => "John", "last_name" => "Smith")
26
28
  ```
27
29
 
28
30
  Application B is subscribed to events
29
31
 
30
32
  ```ruby
31
- # config
32
- ResqueBus.redis = "192.168.1.1:6379"
33
+ # pick an adapter
34
+ require 'resque-bus' # (or other adapter)
33
35
 
34
36
  # initializer
35
- ResqueBus.dispatch("app_b") do
37
+ QueueBus.dispatch("app_b") do
36
38
  # processes event on app_b_default queue
37
39
  # subscribe is short-hand to subscribe to your 'default' queue and this block with process events with the name "user_created"
38
40
  subscribe "user_created" do |attributes|
39
41
  NameCount.find_or_create_by_name(attributes["last_name"]).increment!
40
42
  end
41
-
43
+
42
44
  # processes event on app_b_critical queue
43
45
  # critical is short-hand to subscribe to your 'critical' queue and this block with process events with the name "user_paid"
44
46
  critical "user_paid" do |attributes|
@@ -46,13 +48,13 @@ ResqueBus.dispatch("app_b") do
46
48
  end
47
49
 
48
50
  # you can pass any queue name you would like to process from as well IE: `banana "peeled" do |attributes|`
49
-
51
+
50
52
  # and regexes work as well. note that with the above configuration along with this regex,
51
53
  # the following as well as the corresponding block above would both be executed
52
54
  subscribe /^user_/ do |attributes|
53
55
  Metrics.record_user_action(attributes["bus_event_type"], attributes["id"])
54
56
  end
55
-
57
+
56
58
  # the above all filter on just the event_type, but you can filter on anything
57
59
  # this would be _any_ event that has a user_id and the page value of homepage regardless of bus_event_type
58
60
  subscribe "my_key", { "user_id" => :present, "page" => "homepage"} do
@@ -61,11 +63,11 @@ ResqueBus.dispatch("app_b") do
61
63
  end
62
64
  ```
63
65
 
64
- Applications can also subscribe within classes using the provided `Subscriber` module.
66
+ Applications can also subscribe within classes using the provided `Subscriber` module.
65
67
 
66
68
  ```ruby
67
69
  class SimpleSubscriber
68
- include ResqueBus::Subscriber
70
+ include QueueBus::Subscriber
69
71
  subscribe :my_method
70
72
 
71
73
  def my_method(attributes)
@@ -78,7 +80,7 @@ The following is equivalent to the original initializer and shows more options:
78
80
 
79
81
  ```ruby
80
82
  class OtherSubscriber
81
- include ResqueBus::Subscriber
83
+ include QueueBus::Subscriber
82
84
  application :app_b
83
85
 
84
86
  subscribe :user_created
@@ -110,20 +112,21 @@ Note: This subscribes when this class is loaded, so it needs to be in your load
110
112
 
111
113
  Each app needs to tell Redis about its subscriptions:
112
114
 
113
- $ rake resquebus:subscribe
115
+ $ rake queuebus:subscribe
114
116
 
115
117
  The subscription block is run inside a Resque worker which needs to be started for each app.
116
118
 
117
- $ rake resquebus:setup resque:work
118
-
119
+ $ rake queuebus:setup resque:work
120
+
119
121
  The incoming queue also needs to be processed on a dedicated or all the app servers.
120
122
 
121
- $ rake resquebus:driver resque:work
122
-
123
+ $ rake queuebus:driver resque:work
124
+
123
125
  If you want retry to work for subscribing apps, you should run resque-scheduler
124
-
126
+
125
127
  $ rake resque:scheduler
126
128
 
129
+
127
130
  ### Heartbeat
128
131
 
129
132
  We've found it useful to have the bus act like `cron`, triggering timed jobs throughout the system. Resque Bus calls this a heartbeat.
@@ -133,7 +136,7 @@ It uses resque-scheduler to trigger the events. You can enable it in your Rakefi
133
136
  # resque.rake
134
137
  namespace :resque do
135
138
  task :setup => [:environment] do
136
- ResqueBus.heartbeat!
139
+ QueueBus.heartbeat!
137
140
  end
138
141
  end
139
142
  ```
@@ -143,8 +146,8 @@ Or add it to your `schedule.yml` directly
143
146
  ```yaml
144
147
  resquebus_heartbeat:
145
148
  cron: "* * * * *"
146
- class: "::ResqueBus::Heartbeat"
147
- queue: resquebus_incoming
149
+ class: "::QueueBus::Heartbeat"
150
+ queue: bus_incoming
148
151
  description: "I publish a heartbeat_minutes event every minute"
149
152
  ```
150
153
 
@@ -161,7 +164,7 @@ attributes = {}
161
164
 
162
165
  now = Time.now
163
166
  seconds = now.to_i
164
- ResqueBus.publish("hearbeat_minutes", {
167
+ QueueBus.publish("hearbeat_minutes", {
165
168
  "epoch_seconds" => seconds,
166
169
  "epoch_minutes" => seconds / 1.minute,
167
170
  "epoch_hours" => seconds / 1.hour,
@@ -179,18 +182,18 @@ ResqueBus.publish("hearbeat_minutes", {
179
182
  This allows you do something like this:
180
183
 
181
184
  ```ruby
182
- ResqueBus.dispatch("app_c") do
185
+ QueueBus.dispatch("app_c") do
183
186
  # runs at 10:20, 11:20, etc
184
187
  subscribe "once_an_hour", 'bus_event_type' => 'heartbeat_minutes', 'minute' => 20 do |attributes|
185
188
  Sitemap.generate!
186
189
  end
187
-
190
+
188
191
  # runs every five minutes
189
192
  subscribe "every_five_minutes", 'bus_event_type' => 'heartbeat_minutes' do |attributes|
190
193
  next unless attributes["epoch_minutes"] % 5 == 0
191
194
  HealthCheck.run!
192
195
  end
193
-
196
+
194
197
  # runs at 8am on the first of every month
195
198
  subscribe "new_month_morning", 'bus_event_type' => 'heartbeat_minutes', 'day' => 1, hour' => 8, 'minute' => 0, do |attributes|
196
199
  next unless attributes["epoch_minutes"] % 5 == 0
@@ -199,57 +202,32 @@ ResqueBus.dispatch("app_c") do
199
202
  end
200
203
  ```
201
204
 
202
- ### Compatibility
203
-
204
- ResqueBus can live along side another instance of Resque that points at a different Redis server.
205
-
206
- ```ruby
207
- # config
208
- Resque.redis = "192.168.1.0:6379"
209
- ResqueBus.redis = "192.168.1.1:6379"
210
- ```
211
-
212
- If no Redis instance is given specifically, ResqueBus will use the Resque one.
213
-
214
- ```ruby
215
- # config
216
- Resque.redis = "192.168.1.0:6379"
217
- ```
218
-
219
- That will use the default (resque) namespace which can be helpful for using the tooling. Conflict with queue names are unlikely. You can change the namespace if you like though.
220
-
221
- ```ruby
222
- # config
223
- Resque.redis = "192.168.1.0:6379"
224
- ResqueBus.redis.namespace = :get_on_the_bus
225
- ```
226
-
227
205
  ### Local Mode
228
206
 
229
- For development, a local mode is also provided and is specified in the configuration.
207
+ For development, a local mode is provided and is specified in the configuration.
230
208
 
231
209
  ```ruby
232
210
  # config
233
- ResqueBus.local_mode = :standalone
234
- or
235
- ResqueBus.local_mode = :inline
211
+ QueueBus.local_mode = :standalone
212
+ or
213
+ QueueBus.local_mode = :inline
236
214
  ```
237
215
 
238
- Standalone mode does not require a separate resquebus:driver task to be running to process the
239
- incoming queue. Simply publishing to the bus will distribute the incoming events
240
- to the appropriate application specific queue. A separate resquebus:work task does
216
+ Standalone mode does not require a separate queuebus:driver task to be running to process the
217
+ incoming queue. Simply publishing to the bus will distribute the incoming events
218
+ to the appropriate application specific queue. A separate queuebus:work task does
241
219
  still need to be run to process these events
242
220
 
243
221
  Inline mode skips queue processing entirely and directly dispatches the
244
- event to the appropriate code block.
222
+ event to the appropriate code block.
245
223
 
224
+ You can also say `QueueBus.local_mode = :suppress` to turn off publishing altogether.
225
+ This can be helpful inside some sort of migration, for example.
246
226
 
247
227
  ### TODO
248
228
 
249
- * There are a few spots in the code with TODO notes
229
+ * Replace local modes with adapters
250
230
  * Make this not freak out in development without Redis or when Redis is down
251
231
  * We might not actually need to publish in tests
252
232
  * Add some rspec helpers for the apps to use: should_ post an event_publish or something along those lines
253
- * Allow calling resquebus:setup and resquebus:driver together (append to ENV['QUEUES'], don't replace it)
254
-
255
- Copyright (c) 2011 Brian Leonard, released under the MIT license
233
+ * Allow calling queuebus:setup and queuebus:driver together (append to ENV['QUEUES'], don't replace it)
data/Rakefile CHANGED
@@ -1,3 +1,2 @@
1
1
  $LOAD_PATH.unshift 'lib'
2
- require 'resque/tasks'
3
2
  require 'resque_bus/tasks'
data/lib/resque-bus.rb CHANGED
@@ -1,311 +1,19 @@
1
+ require "queue-bus"
2
+ require "resque_bus/adapter"
1
3
  require "resque_bus/version"
2
4
 
3
- require 'redis/namespace'
4
- require 'resque'
5
-
6
- module QueueBus
7
- autoload :Worker, 'resque_bus/compatibility'
8
- end
9
-
10
5
  module ResqueBus
11
-
12
- autoload :Application, 'resque_bus/application'
13
- autoload :Dispatch, 'resque_bus/dispatch'
14
- autoload :Driver, 'resque_bus/driver'
15
- autoload :Heartbeat, 'resque_bus/heartbeat'
16
- autoload :Local, 'resque_bus/local'
17
- autoload :Matcher, 'resque_bus/matcher'
18
- autoload :Publisher, 'resque_bus/publisher'
19
- autoload :Rider, 'resque_bus/rider'
20
- autoload :Subscriber, 'resque_bus/subscriber'
21
- autoload :Subscription, 'resque_bus/subscription'
22
- autoload :SubscriptionList, 'resque_bus/subscription_list'
23
- autoload :TaskManager, 'resque_bus/task_manager'
24
- autoload :Util, 'resque_bus/util'
25
-
26
- class << self
27
-
28
- def default_app_key=val
29
- @default_app_key = Application.normalize(val)
30
- end
31
-
32
- def default_app_key
33
- @default_app_key
34
- end
35
-
36
- def default_queue=val
37
- @default_queue = val
38
- end
39
-
40
- def default_queue
41
- @default_queue
42
- end
43
-
44
- def hostname
45
- @hostname ||= `hostname 2>&1`.strip.sub(/.local/,'')
46
- end
47
-
48
- def dispatch(app_key=nil, &block)
49
- dispatcher = dispatcher_by_key(app_key)
50
- dispatcher.instance_eval(&block)
51
- dispatcher
52
- end
53
-
54
- def dispatchers
55
- @dispatchers ||= {}
56
- @dispatchers.values
57
- end
58
-
59
- def dispatcher_by_key(app_key)
60
- app_key = Application.normalize(app_key || default_app_key)
61
- @dispatchers ||= {}
62
- @dispatchers[app_key] ||= Dispatch.new(app_key)
63
- end
64
-
65
- def dispatcher_execute(app_key, key, attributes)
66
- @dispatchers ||= {}
67
- dispatcher = @dispatchers[app_key]
68
- dispatcher.execute(key, attributes) if dispatcher
69
- end
70
-
71
- def local_mode=value
72
- @local_mode = value
73
- end
74
-
75
- def local_mode
76
- @local_mode
77
- end
78
-
79
- def heartbeat!
80
- # turn on the heartbeat
81
- # should be down after loading scheduler yml if you do that
82
- # otherwise, anytime
83
- require 'resque/scheduler'
84
- name = 'resquebus_hearbeat'
85
- schedule = { 'class' => '::ResqueBus::Heartbeat',
86
- 'cron' => '* * * * *', # every minute
87
- 'queue' => incoming_queue,
88
- 'description' => 'I publish a heartbeat_minutes event every minute'
89
- }
90
- if Resque::Scheduler.dynamic
91
- Resque.set_schedule(name, schedule)
92
- end
93
- Resque.schedule[name] = schedule
94
- end
6
+ # TODO: all of this will be removed
95
7
 
96
- # Accepts:
97
- # 1. A 'hostname:port' String
98
- # 2. A 'hostname:port:db' String (to select the Redis db)
99
- # 3. A 'hostname:port/namespace' String (to set the Redis namespace)
100
- # 4. A Redis URL String 'redis://host:port'
101
- # 5. An instance of `Redis`, `Redis::Client`, `Redis::DistRedis`,
102
- # or `Redis::Namespace`.
103
- def redis=(server)
104
- case server
105
- when String
106
- if server =~ /redis\:\/\//
107
- redis = Redis.connect(:url => server, :thread_safe => true)
108
- else
109
- server, namespace = server.split('/', 2)
110
- host, port, db = server.split(':')
111
- redis = Redis.new(:host => host, :port => port,
112
- :thread_safe => true, :db => db)
113
- end
114
- namespace ||= default_namespace
8
+ autoload :Deprecated, 'resque_bus/compatibility/deprecated'
9
+ autoload :Subscriber, 'resque_bus/compatibility/subscriber'
10
+ autoload :TaskManager, 'resque_bus/compatibility/task_manager'
11
+ autoload :Driver, 'resque_bus/compatibility/driver'
12
+ autoload :Rider, 'resque_bus/compatibility/rider'
13
+ autoload :Publisher, 'resque_bus/compatibility/publisher'
14
+ autoload :Heartbeat, 'resque_bus/compatibility/heartbeat'
115
15
 
116
- @redis = Redis::Namespace.new(namespace, :redis => redis)
117
- when Redis::Namespace
118
- @redis = server
119
- else
120
- @redis = Redis::Namespace.new(default_namespace, :redis => server)
121
- end
122
- end
123
-
124
- # Returns the current Redis connection. If none has been created, will
125
- # create a new one from the Reqsue one (with a different namespace)
126
- def redis
127
- return @redis if @redis
128
- copy = Resque.redis.clone
129
- copy.namespace = default_namespace
130
- self.redis = copy
131
- self.redis
132
- end
133
-
134
- def original_redis=(server)
135
- @original_redis = server
136
- end
137
- def original_redis
138
- @original_redis
139
- end
140
-
141
- def with_global_attributes(attributes)
142
- original_timezone = false
143
- original_locale = false
144
-
145
- if attributes["bus_locale"] && defined?(I18n) && I18n.respond_to?(:locale=)
146
- original_locale = I18n.locale if I18n.respond_to?(:locale)
147
- I18n.locale = attributes["bus_locale"]
148
- end
149
-
150
- if attributes["bus_timezone"] && defined?(Time) && Time.respond_to?(:zone=)
151
- original_timezone = Time.zone if Time.respond_to?(:zone)
152
- Time.zone = attributes["bus_timezone"]
153
- end
154
-
155
- yield
156
- ensure
157
- I18n.locale = original_locale unless original_locale == false
158
- Time.zone = original_timezone unless original_timezone == false
159
- end
160
-
161
- def before_publish=(proc)
162
- @before_publish_callback = proc
163
- end
164
-
165
- def before_publish_callback(attributes)
166
- if @before_publish_callback
167
- @before_publish_callback.call(attributes)
168
- end
169
- end
170
-
171
-
172
- def publish_metadata(event_type, attributes={})
173
- # TODO: "bus_app_key" => application.app_key ?
174
- bus_attr = {"bus_published_at" => Time.now.to_i, "bus_event_type" => event_type}
175
- bus_attr["bus_id"] = "#{Time.now.to_i}-#{generate_uuid}"
176
- bus_attr["bus_app_hostname"] = hostname
177
- bus_attr["bus_locale"] = I18n.locale.to_s if defined?(I18n) && I18n.respond_to?(:locale) && I18n.locale
178
- bus_attr["bus_timezone"] = Time.zone.name if defined?(Time) && Time.respond_to?(:zone) && Time.zone
179
- out = bus_attr.merge(attributes || {})
180
- ResqueBus.before_publish_callback(out)
181
- out
182
- end
183
-
184
- def generate_uuid
185
- require 'securerandom' unless defined?(SecureRandom)
186
- return SecureRandom.uuid
187
-
188
- rescue Exception => e
189
- # secure random not there
190
- # big random number a few times
191
- n_bytes = [42].pack('i').size
192
- n_bits = n_bytes * 8
193
- max = 2 ** (n_bits - 2) - 1
194
- return "#{rand(max)}-#{rand(max)}-#{rand(max)}"
195
- end
196
-
197
- def publish(event_type, attributes = {})
198
- to_publish = publish_metadata(event_type, attributes)
199
- ResqueBus.log_application("Event published: #{event_type} #{to_publish.inspect}")
200
- if local_mode
201
- ResqueBus::Local.perform(to_publish)
202
- else
203
- enqueue_to(incoming_queue, Driver, to_publish)
204
- end
205
- end
206
-
207
- def publish_at(timestamp_or_epoch, event_type, attributes = {})
208
- to_publish = publish_metadata(event_type, attributes)
209
- to_publish["bus_delayed_until"] ||= timestamp_or_epoch.to_i
210
- to_publish.delete("bus_published_at") unless attributes["bus_published_at"] # will be put on when it actually does it
211
-
212
- ResqueBus.log_application("Event published:#{event_type} #{to_publish.inspect} publish_at: #{timestamp_or_epoch.to_i}")
213
- item = delayed_job_to_hash_with_queue(incoming_queue, Publisher, [event_type, to_publish])
214
- delayed_push(timestamp_or_epoch, item)
215
- end
216
-
217
- def enqueue_to(queue, klass, *args)
218
- push(queue, :class => klass.to_s, :args => args)
219
- end
220
-
221
- def logger
222
- @logger
223
- end
224
-
225
- def logger=val
226
- @logger = val
227
- end
228
-
229
- def log_application(message)
230
- if logger
231
- time = Time.now.strftime('%H:%M:%S %Y-%m-%d')
232
- logger.info("** [#{time}] #$$: ResqueBus #{message}")
233
- end
234
- end
235
-
236
- def log_worker(message)
237
- if ENV['LOGGING'] || ENV['VERBOSE'] || ENV['VVERBOSE']
238
- time = Time.now.strftime('%H:%M:%S %Y-%m-%d')
239
- puts "** [#{time}] #$$: #{message}"
240
- end
241
- end
242
-
243
- protected
244
-
245
- def reset
246
- # used by tests
247
- @redis = nil # clear instance of redis
248
- @dispatcher = nil
249
- @default_app_key = nil
250
- @default_queue = nil
251
- @before_publish_callback = nil
252
- end
253
-
254
- def incoming_queue
255
- "resquebus_incoming"
256
- end
257
-
258
- def default_namespace
259
- # It might play better on the same server, but overall life is more complicated
260
- :resque
261
- end
262
-
263
- ## From Resque, but using a (possibly) different instance of Redis
264
-
265
- # Pushes a job onto a queue. Queue name should be a string and the
266
- # item should be any JSON-able Ruby object.
267
- #
268
- # Resque works generally expect the `item` to be a hash with the following
269
- # keys:
270
- #
271
- # class - The String name of the job to run.
272
- # args - An Array of arguments to pass the job. Usually passed
273
- # via `class.to_class.perform(*args)`.
274
- #
275
- # Example
276
- #
277
- # Resque.push('archive', :class => 'Archive', :args => [ 35, 'tar' ])
278
- #
279
- # Returns nothing
280
- def push(queue, item)
281
- watch_queue(queue)
282
- redis.rpush "queue:#{queue}", Resque.encode(item)
283
- end
284
-
285
- # Used internally to keep track of which queues we've created.
286
- # Don't call this directly.
287
- def watch_queue(queue)
288
- redis.sadd(:queues, queue.to_s)
289
- end
290
-
291
- ### From Resque Scheduler
292
- # Used internally to stuff the item into the schedule sorted list.
293
- # +timestamp+ can be either in seconds or a datetime object
294
- # Insertion if O(log(n)).
295
- # Returns true if it's the first job to be scheduled at that time, else false
296
- def delayed_push(timestamp, item)
297
- # First add this item to the list for this timestamp
298
- redis.rpush("delayed:#{timestamp.to_i}", Resque.encode(item))
16
+ extend ::ResqueBus::Deprecated
17
+ end
299
18
 
300
- # Now, add this timestamp to the zsets. The score and the value are
301
- # the same since we'll be querying by timestamp, and we don't have
302
- # anything else to store.
303
- redis.zadd :delayed_queue_schedule, timestamp.to_i, timestamp.to_i
304
- end
305
-
306
- def delayed_job_to_hash_with_queue(queue, klass, args)
307
- {:class => klass.to_s, :args => args, :queue => queue}
308
- end
309
- end
310
-
311
- end
19
+ QueueBus.adapter = QueueBus::Adapters::Resque.new
@@ -0,0 +1,65 @@
1
+ module QueueBus
2
+ module Adapters
3
+ class Resque < QueueBus::Adapters::Base
4
+ def enabled!
5
+ # know we are using it
6
+ require 'resque'
7
+ require 'resque/scheduler'
8
+ require 'resque-retry'
9
+
10
+ QueueBus::Worker.extend(::Resque::Plugins::ExponentialBackoff)
11
+ QueueBus::Worker.extend(::QueueBus::Adapters::Resque::RetryHandlers)
12
+ end
13
+
14
+ def redis(&block)
15
+ block.call(::Resque.redis)
16
+ end
17
+
18
+ def enqueue(queue_name, klass, json)
19
+ ::Resque.enqueue_to(queue_name, klass, json)
20
+ end
21
+
22
+ def enqueue_at(epoch_seconds, queue_name, klass, json)
23
+ ::Resque.enqueue_at_with_queue(queue_name, epoch_seconds, klass, json)
24
+ end
25
+
26
+ def setup_heartbeat!(queue_name)
27
+ # turn on the heartbeat
28
+ # should be down after loading scheduler yml if you do that
29
+ # otherwise, anytime
30
+ name = 'resquebus_heartbeat'
31
+ schedule = { 'class' => '::QueueBus::Heartbeat',
32
+ 'cron' => '* * * * *', # every minute
33
+ 'queue' => queue_name,
34
+ 'description' => 'I publish a heartbeat_minutes event every minute'
35
+ }
36
+ if ::Resque::Scheduler.dynamic
37
+ ::Resque.set_schedule(name, schedule)
38
+ end
39
+ ::Resque.schedule[name] = schedule
40
+ end
41
+
42
+ private
43
+
44
+ module RetryHandlers
45
+ # @failure_hooks_already_ran on https://github.com/defunkt/resque/tree/1-x-stable
46
+ # to prevent running twice
47
+ def queue
48
+ @my_queue
49
+ end
50
+
51
+ def on_failure_aaa(exception, *args)
52
+ # note: sorted alphabetically
53
+ # queue needs to be set for rety to work (know what queue in Requeue.class_to_queue)
54
+ hash = ::QueueBus::Util.decode(args[0])
55
+ @my_queue = hash["bus_rider_queue"]
56
+ end
57
+
58
+ def on_failure_zzz(exception, *args)
59
+ # note: sorted alphabetically
60
+ @my_queue = nil
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,38 @@
1
+ module ResqueBus
2
+ module Deprecated
3
+ def show_deprecations=val
4
+ @show_deprecations = val
5
+ end
6
+
7
+ def show_deprecations?
8
+ return @show_deprecations if defined?(@show_deprecations)
9
+ return true if !ENV['QUEUES'] && !ENV['QUEUE'] # not in background, probably test
10
+ return true if ENV['VVERBOSE'] || ENV['LOGGING'] || ENV['VERBOSE']
11
+ false
12
+ end
13
+
14
+ def note_deprecation(message)
15
+ @noted_deprecations ||= {}
16
+ if @noted_deprecations[message]
17
+ @noted_deprecations[message] += 1
18
+ else
19
+ warn(message) if show_deprecations?
20
+ @noted_deprecations[message] = 1
21
+ end
22
+ end
23
+
24
+ def redis
25
+ ResqueBus.note_deprecation "[DEPRECATION] ResqueBus direct usage is deprecated. Use `QueueBus.redis` instead. Note that it also requires block usage now."
26
+ ::Resque.redis
27
+ end
28
+
29
+ def redis=val
30
+ ResqueBus.note_deprecation "[DEPRECATION] ResqueBus can no longer set redis directly. It will use Resque's instance of redis."
31
+ end
32
+
33
+ def method_missing(method_name, *args, &block)
34
+ ResqueBus.note_deprecation "[DEPRECATION] ResqueBus direct usage is deprecated. Use `QueueBus.#{method_name}` instead."
35
+ ::QueueBus.send(method_name, *args, &block)
36
+ end
37
+ end
38
+ end