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.
- data/.gitignore +1 -0
- data/Gemfile +2 -2
- data/README.mdown +42 -64
- data/Rakefile +0 -1
- data/lib/resque-bus.rb +13 -305
- data/lib/resque_bus/adapter.rb +65 -0
- data/lib/resque_bus/compatibility/deprecated.rb +38 -0
- data/lib/resque_bus/compatibility/driver.rb +10 -0
- data/lib/resque_bus/compatibility/heartbeat.rb +10 -0
- data/lib/resque_bus/compatibility/publisher.rb +13 -0
- data/lib/resque_bus/compatibility/rider.rb +32 -0
- data/lib/resque_bus/compatibility/subscriber.rb +8 -0
- data/lib/resque_bus/compatibility/task_manager.rb +8 -0
- data/lib/resque_bus/server/views/bus.erb +2 -2
- data/lib/resque_bus/server.rb +5 -4
- data/lib/resque_bus/tasks.rb +46 -46
- data/lib/resque_bus/version.rb +2 -4
- data/resque-bus.gemspec +5 -10
- data/spec/adapter/compatibility_spec.rb +97 -0
- data/spec/adapter/integration_spec.rb +111 -0
- data/spec/adapter/publish_at_spec.rb +50 -0
- data/spec/adapter/retry_spec.rb +47 -0
- data/spec/adapter/support.rb +23 -0
- data/spec/adapter_spec.rb +14 -0
- data/spec/application_spec.rb +62 -62
- data/spec/config_spec.rb +83 -0
- data/spec/dispatch_spec.rb +6 -6
- data/spec/driver_spec.rb +62 -44
- data/spec/heartbeat_spec.rb +4 -4
- data/spec/integration_spec.rb +2 -2
- data/spec/matcher_spec.rb +29 -29
- data/spec/publish_spec.rb +46 -43
- data/spec/publisher_spec.rb +7 -0
- data/spec/rider_spec.rb +14 -66
- data/spec/spec_helper.rb +25 -25
- data/spec/subscriber_spec.rb +194 -176
- data/spec/subscription_list_spec.rb +1 -1
- data/spec/subscription_spec.rb +1 -1
- data/spec/worker_spec.rb +32 -0
- metadata +47 -58
- data/lib/resque_bus/application.rb +0 -115
- data/lib/resque_bus/compatibility.rb +0 -24
- data/lib/resque_bus/dispatch.rb +0 -61
- data/lib/resque_bus/driver.rb +0 -30
- data/lib/resque_bus/heartbeat.rb +0 -106
- data/lib/resque_bus/local.rb +0 -38
- data/lib/resque_bus/matcher.rb +0 -81
- data/lib/resque_bus/publisher.rb +0 -12
- data/lib/resque_bus/rider.rb +0 -54
- data/lib/resque_bus/subscriber.rb +0 -63
- data/lib/resque_bus/subscription.rb +0 -55
- data/lib/resque_bus/subscription_list.rb +0 -53
- data/lib/resque_bus/task_manager.rb +0 -52
- data/lib/resque_bus/util.rb +0 -42
- data/lib/tasks/resquebus.rake +0 -2
- data/spec/compatibility_spec.rb +0 -93
- data/spec/publish_at_spec.rb +0 -74
- data/spec/redis_spec.rb +0 -13
@@ -1,63 +0,0 @@
|
|
1
|
-
module ResqueBus
|
2
|
-
module Subscriber
|
3
|
-
|
4
|
-
def self.included(base)
|
5
|
-
base.extend ClassMethods
|
6
|
-
end
|
7
|
-
|
8
|
-
module ClassMethods
|
9
|
-
|
10
|
-
def application(app_key)
|
11
|
-
@app_key = ::ResqueBus::Application.normalize(app_key)
|
12
|
-
end
|
13
|
-
|
14
|
-
def app_key
|
15
|
-
return @app_key if @app_key
|
16
|
-
@app_key = ::ResqueBus.default_app_key
|
17
|
-
return @app_key if @app_key
|
18
|
-
# module or class_name
|
19
|
-
val = self.name.to_s.split("::").first
|
20
|
-
@app_key = ::ResqueBus::Util.underscore(val)
|
21
|
-
end
|
22
|
-
|
23
|
-
def subscribe(method_name, matcher_hash = nil)
|
24
|
-
queue_name = ::Resque.queue_from_class(self)
|
25
|
-
queue_name ||= ::ResqueBus.default_queue
|
26
|
-
queue_name ||= "#{app_key}_default"
|
27
|
-
subscribe_queue(queue_name, method_name, matcher_hash)
|
28
|
-
end
|
29
|
-
|
30
|
-
def subscribe_queue(queue_name, method_name, matcher_hash = nil)
|
31
|
-
klass = self
|
32
|
-
matcher_hash ||= {"bus_event_type" => method_name}
|
33
|
-
sub_key = "#{self.name}.#{method_name}"
|
34
|
-
dispatcher = ::ResqueBus.dispatcher_by_key(app_key)
|
35
|
-
dispatcher.add_subscription(queue_name, sub_key, klass.name.to_s, matcher_hash, lambda{ |att| klass.perform(att) })
|
36
|
-
end
|
37
|
-
|
38
|
-
def transform(method_name)
|
39
|
-
@transform = method_name
|
40
|
-
end
|
41
|
-
|
42
|
-
def perform(attributes)
|
43
|
-
ResqueBus.with_global_attributes(attributes) do
|
44
|
-
sub_key = attributes["bus_rider_sub_key"]
|
45
|
-
meth_key = sub_key.split(".").last
|
46
|
-
resque_bus_execute(meth_key, attributes)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def resque_bus_execute(key, attributes)
|
51
|
-
args = attributes
|
52
|
-
args = send(@transform, attributes) if @transform
|
53
|
-
args = [args] unless args.is_a?(Array)
|
54
|
-
if self.respond_to?(:subscriber_with_attributes)
|
55
|
-
me = self.subscriber_with_attributes(attributes)
|
56
|
-
else
|
57
|
-
me = self.new
|
58
|
-
end
|
59
|
-
me.send(key, *args)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
module ResqueBus
|
2
|
-
class Subscription
|
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
|
21
|
-
end
|
22
|
-
|
23
|
-
attr_reader :matcher, :executor, :queue_name, :key, :class_name
|
24
|
-
attr_accessor :app_key # dyanmically set on return from subscription_matches
|
25
|
-
|
26
|
-
def initialize(queue_name, key, class_name, filters, executor=nil)
|
27
|
-
@queue_name = self.class.normalize(queue_name)
|
28
|
-
@key = key.to_s
|
29
|
-
@class_name = class_name.to_s
|
30
|
-
@matcher = Matcher.new(filters)
|
31
|
-
@executor = executor
|
32
|
-
end
|
33
|
-
|
34
|
-
def execute!(attributes)
|
35
|
-
attributes = attributes.with_indifferent_access if attributes.respond_to?(:with_indifferent_access)
|
36
|
-
ResqueBus.with_global_attributes(attributes) do
|
37
|
-
executor.call(attributes)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def matches?(attributes)
|
42
|
-
@matcher.matches?(attributes)
|
43
|
-
end
|
44
|
-
|
45
|
-
def to_redis
|
46
|
-
out = {}
|
47
|
-
out["queue_name"] = queue_name
|
48
|
-
out["key"] = key
|
49
|
-
out["class"] = class_name
|
50
|
-
out["matcher"] = matcher.to_redis
|
51
|
-
out
|
52
|
-
end
|
53
|
-
|
54
|
-
end
|
55
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
module ResqueBus
|
2
|
-
class SubscriptionList
|
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
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def to_redis
|
18
|
-
out = {}
|
19
|
-
@subscriptions.values.each do |sub|
|
20
|
-
out[sub.key] = sub.to_redis
|
21
|
-
end
|
22
|
-
out
|
23
|
-
end
|
24
|
-
|
25
|
-
def initialize
|
26
|
-
@subscriptions = {}
|
27
|
-
end
|
28
|
-
|
29
|
-
def add(sub)
|
30
|
-
@subscriptions[sub.key] = sub
|
31
|
-
end
|
32
|
-
|
33
|
-
def size
|
34
|
-
@subscriptions.size
|
35
|
-
end
|
36
|
-
|
37
|
-
def key(key)
|
38
|
-
@subscriptions[key.to_s]
|
39
|
-
end
|
40
|
-
|
41
|
-
def all
|
42
|
-
@subscriptions.values
|
43
|
-
end
|
44
|
-
|
45
|
-
def matches(attributes)
|
46
|
-
out = []
|
47
|
-
all.each do |sub|
|
48
|
-
out << sub if sub.matches?(attributes)
|
49
|
-
end
|
50
|
-
out
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
@@ -1,52 +0,0 @@
|
|
1
|
-
module ResqueBus
|
2
|
-
class TaskManager
|
3
|
-
|
4
|
-
attr_reader :logging
|
5
|
-
|
6
|
-
def initialize(logging)
|
7
|
-
@logging = logging
|
8
|
-
end
|
9
|
-
|
10
|
-
def subscribe!
|
11
|
-
count = 0
|
12
|
-
ResqueBus.dispatchers.each do |dispatcher|
|
13
|
-
subscriptions = dispatcher.subscriptions
|
14
|
-
if subscriptions.size > 0
|
15
|
-
count += subscriptions.size
|
16
|
-
log "Subscribing #{dispatcher.app_key} to #{subscriptions.size} subscriptions"
|
17
|
-
app = ResqueBus::Application.new(dispatcher.app_key)
|
18
|
-
app.subscribe(subscriptions, logging)
|
19
|
-
log " ...done"
|
20
|
-
end
|
21
|
-
end
|
22
|
-
count
|
23
|
-
end
|
24
|
-
|
25
|
-
def unsubscribe!
|
26
|
-
count = 0
|
27
|
-
ResqueBus.dispatchers.each do |dispatcher|
|
28
|
-
log "Unsubcribing from #{dispatcher.app_key}"
|
29
|
-
app = ResqueBus::Application.new(dispatcher.app_key)
|
30
|
-
app.unsubscribe
|
31
|
-
count += 1
|
32
|
-
log " ...done"
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def queue_names
|
37
|
-
# let's not talk to redis in here. Seems to screw things up
|
38
|
-
queues = []
|
39
|
-
ResqueBus.dispatchers.each do |dispatcher|
|
40
|
-
dispatcher.subscriptions.all.each do |sub|
|
41
|
-
queues << sub.queue_name
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
queues.uniq
|
46
|
-
end
|
47
|
-
|
48
|
-
def log(message)
|
49
|
-
puts(message) if logging
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
data/lib/resque_bus/util.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
module ResqueBus
|
2
|
-
module Util
|
3
|
-
extend self
|
4
|
-
|
5
|
-
def underscore(camel_cased_word)
|
6
|
-
word = camel_cased_word.to_s.dup
|
7
|
-
word.gsub!('::', '/')
|
8
|
-
# word.gsub!(/(?:([A-Za-z\d])|^)(#{inflections.acronym_regex})(?=\b|[^a-z])/) { "#{$1}#{$1 && '_'}#{$2.downcase}" }
|
9
|
-
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
|
10
|
-
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
11
|
-
word.tr!("-", "_")
|
12
|
-
word.downcase!
|
13
|
-
word
|
14
|
-
end
|
15
|
-
|
16
|
-
def constantize(camel_cased_word)
|
17
|
-
names = camel_cased_word.split('::')
|
18
|
-
names.shift if names.empty? || names.first.empty?
|
19
|
-
|
20
|
-
names.inject(Object) do |constant, name|
|
21
|
-
if constant == Object
|
22
|
-
constant.const_get(name)
|
23
|
-
else
|
24
|
-
candidate = constant.const_get(name)
|
25
|
-
next candidate if constant.const_defined?(name, false)
|
26
|
-
next candidate unless Object.const_defined?(name)
|
27
|
-
|
28
|
-
# Go down the ancestors to check it it's owned
|
29
|
-
# directly before we reach Object or the end of ancestors.
|
30
|
-
constant = constant.ancestors.inject do |const, ancestor|
|
31
|
-
break const if ancestor == Object
|
32
|
-
break ancestor if ancestor.const_defined?(name, false)
|
33
|
-
const
|
34
|
-
end
|
35
|
-
|
36
|
-
# owner is in Object, so raise
|
37
|
-
constant.const_get(name, false)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
data/lib/tasks/resquebus.rake
DELETED
data/spec/compatibility_spec.rb
DELETED
@@ -1,93 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe "migration compatibility" do
|
4
|
-
before(:each) do
|
5
|
-
ResqueBus.dispatch("r1") do
|
6
|
-
subscribe "event_name" do |attributes|
|
7
|
-
ResqueBus::Runner1.run(attributes)
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
ResqueBus::TaskManager.new(false).subscribe!
|
12
|
-
|
13
|
-
@incoming = Resque::Worker.new(:resquebus_incoming)
|
14
|
-
@incoming.register_worker
|
15
|
-
|
16
|
-
@new_incoming = Resque::Worker.new(:bus_incoming)
|
17
|
-
@new_incoming.register_worker
|
18
|
-
|
19
|
-
@rider = Resque::Worker.new(:r1_default)
|
20
|
-
@rider.register_worker
|
21
|
-
end
|
22
|
-
|
23
|
-
it "should still drive as expected" do
|
24
|
-
val = ResqueBus.redis.lpop("queue:bus_incoming")
|
25
|
-
val.should == nil
|
26
|
-
|
27
|
-
args = [ JSON.generate({"bus_class_proxy"=>"QueueBus::Driver", "bus_event_type" => "event_name", "two"=>"here", "one"=>1, "id" => 12}) ]
|
28
|
-
item = {:class => "QueueBus::Worker", :args => args}
|
29
|
-
|
30
|
-
ResqueBus.redis.sadd(:queues, "bus_incoming")
|
31
|
-
ResqueBus.redis.rpush "queue:bus_incoming", Resque.encode(item)
|
32
|
-
|
33
|
-
ResqueBus::Runner1.value.should == 0
|
34
|
-
|
35
|
-
perform_next_job @new_incoming
|
36
|
-
|
37
|
-
ResqueBus::Runner1.value.should == 0
|
38
|
-
|
39
|
-
perform_next_job @rider
|
40
|
-
|
41
|
-
ResqueBus::Runner1.value.should == 1
|
42
|
-
end
|
43
|
-
|
44
|
-
it "should still ride as expected" do
|
45
|
-
val = ResqueBus.redis.lpop("queue:r1_default")
|
46
|
-
val.should == nil
|
47
|
-
|
48
|
-
args = [ {"bus_rider_app_key"=>"r1", "x" => "y", "bus_event_type" => "event_name",
|
49
|
-
"bus_rider_sub_key"=>"event_name", "bus_rider_queue" => "default",
|
50
|
-
"bus_rider_class_name"=>"::ResqueBus::Rider"}]
|
51
|
-
item = {:class => "ResqueBus::Rider", :args => args}
|
52
|
-
|
53
|
-
args = [ JSON.generate({"bus_class_proxy"=>"QueueBus::Rider","bus_rider_app_key"=>"r1", "x" => "y",
|
54
|
-
"bus_event_type" => "event_name", "bus_rider_sub_key"=>"event_name",
|
55
|
-
"bus_rider_queue" => "default"}) ]
|
56
|
-
item = {:class => "QueueBus::Worker", :args => args}
|
57
|
-
|
58
|
-
ResqueBus.redis.sadd(:queues, "r1_default")
|
59
|
-
ResqueBus.redis.rpush "queue:r1_default", Resque.encode(item)
|
60
|
-
|
61
|
-
ResqueBus::Runner1.value.should == 0
|
62
|
-
|
63
|
-
perform_next_job @rider
|
64
|
-
|
65
|
-
ResqueBus::Runner1.value.should == 1
|
66
|
-
end
|
67
|
-
|
68
|
-
it "should still publish as expected" do
|
69
|
-
val = ResqueBus.redis.lpop("queue:bus_incoming")
|
70
|
-
val.should == nil
|
71
|
-
|
72
|
-
args = [ JSON.generate({"bus_class_proxy" => "QueueBus::Publisher", "bus_event_type"=>"event_name", "two"=>"here", "one"=>1, "id" => 12}) ]
|
73
|
-
item = {:class => "QueueBus::Worker", :args => args}
|
74
|
-
|
75
|
-
ResqueBus.redis.sadd(:queues, "bus_incoming")
|
76
|
-
ResqueBus.redis.rpush "queue:bus_incoming", Resque.encode(item)
|
77
|
-
|
78
|
-
ResqueBus::Runner1.value.should == 0
|
79
|
-
|
80
|
-
perform_next_job @new_incoming # publish
|
81
|
-
|
82
|
-
ResqueBus::Runner1.value.should == 0
|
83
|
-
|
84
|
-
perform_next_job @incoming # drive
|
85
|
-
|
86
|
-
ResqueBus::Runner1.value.should == 0
|
87
|
-
|
88
|
-
perform_next_job @rider # ride
|
89
|
-
|
90
|
-
ResqueBus::Runner1.value.should == 1
|
91
|
-
|
92
|
-
end
|
93
|
-
end
|
data/spec/publish_at_spec.rb
DELETED
@@ -1,74 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe "Publishing an event in the future" do
|
4
|
-
|
5
|
-
before(:each) do
|
6
|
-
Timecop.freeze(now)
|
7
|
-
ResqueBus.stub(:generate_uuid).and_return("idfhlkj")
|
8
|
-
end
|
9
|
-
after(:each) do
|
10
|
-
Timecop.return
|
11
|
-
end
|
12
|
-
let(:delayed_attrs) { {"bus_delayed_until" => future.to_i,
|
13
|
-
"bus_id" => "#{now.to_i}-idfhlkj",
|
14
|
-
"bus_app_hostname" => `hostname 2>&1`.strip.sub(/.local/,'')} }
|
15
|
-
|
16
|
-
let(:bus_attrs) { delayed_attrs.merge({"bus_published_at" => worktime.to_i})}
|
17
|
-
let(:now) { Time.parse("01/01/2013 5:00")}
|
18
|
-
let(:future) { Time.at(now.to_i + 60) }
|
19
|
-
let(:worktime) {Time.at(future.to_i + 1)}
|
20
|
-
|
21
|
-
it "should add it to Redis" do
|
22
|
-
hash = {:one => 1, "two" => "here", "id" => 12 }
|
23
|
-
event_name = "event_name"
|
24
|
-
ResqueBus.publish_at(future, event_name, hash)
|
25
|
-
|
26
|
-
schedule = ResqueBus.redis.zrange("delayed_queue_schedule", 0, 1)
|
27
|
-
schedule.should == [future.to_i.to_s]
|
28
|
-
|
29
|
-
val = ResqueBus.redis.lpop("delayed:#{future.to_i}")
|
30
|
-
hash = JSON.parse(val)
|
31
|
-
|
32
|
-
hash["class"].should == "ResqueBus::Publisher"
|
33
|
-
hash["args"].should == [ "event_name", {"bus_event_type"=>"event_name", "two"=>"here", "one"=>1, "id" => 12}.merge(delayed_attrs) ]
|
34
|
-
hash["queue"].should == "resquebus_incoming"
|
35
|
-
end
|
36
|
-
|
37
|
-
it "should move it to the real queue when processing" do
|
38
|
-
hash = {:one => 1, "two" => "here", "id" => 12 }
|
39
|
-
event_name = "event_name"
|
40
|
-
|
41
|
-
val = ResqueBus.redis.lpop("queue:resquebus_incoming")
|
42
|
-
val.should == nil
|
43
|
-
|
44
|
-
ResqueBus.publish_at(future, event_name, hash)
|
45
|
-
|
46
|
-
val = ResqueBus.redis.lpop("queue:resquebus_incoming")
|
47
|
-
val.should == nil # nothing really added
|
48
|
-
|
49
|
-
# process sceduler now
|
50
|
-
Resque::Scheduler.handle_delayed_items
|
51
|
-
|
52
|
-
val = ResqueBus.redis.lpop("queue:resquebus_incoming")
|
53
|
-
val.should == nil # nothing added yet
|
54
|
-
|
55
|
-
# process scheduler in future
|
56
|
-
Timecop.freeze(worktime) do
|
57
|
-
Resque::Scheduler.handle_delayed_items
|
58
|
-
|
59
|
-
# added
|
60
|
-
val = ResqueBus.redis.lpop("queue:resquebus_incoming")
|
61
|
-
hash = JSON.parse(val)
|
62
|
-
hash["class"].should == "ResqueBus::Publisher"
|
63
|
-
hash["args"].should == [ "event_name", {"bus_event_type"=>"event_name", "two"=>"here", "one"=>1, "id" => 12}.merge(delayed_attrs) ]
|
64
|
-
|
65
|
-
ResqueBus::Publisher.perform(*hash["args"])
|
66
|
-
|
67
|
-
val = ResqueBus.redis.lpop("queue:resquebus_incoming")
|
68
|
-
hash = JSON.parse(val)
|
69
|
-
hash["class"].should == "ResqueBus::Driver"
|
70
|
-
hash["args"].should == [ {"bus_event_type"=>"event_name", "two"=>"here", "one"=>1, "id" => 12}.merge(bus_attrs) ]
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
end
|
data/spec/redis_spec.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe "Redis Connection" do
|
4
|
-
it "should use the one specified if given" do
|
5
|
-
ResqueBus.redis = "localhost:9379"
|
6
|
-
ResqueBus.redis.instance_variable_get("@redis").client.port.should == 9379
|
7
|
-
Resque.redis.instance_variable_get("@redis").client.port.should == 6379
|
8
|
-
end
|
9
|
-
it "should use the default Resque connection if none specified" do
|
10
|
-
ResqueBus.redis.instance_variable_get("@redis").client.port.should == 6379
|
11
|
-
Resque.redis.instance_variable_get("@redis").client.port.should == 6379
|
12
|
-
end
|
13
|
-
end
|