aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport
diff options
context:
space:
mode:
authorCarlhuda <carlhuda@engineyard.com>2010-03-01 17:33:59 -0800
committerCarlhuda <carlhuda@engineyard.com>2010-03-01 17:45:37 -0800
commitfc0882ba5a0f18281736859718252042b15614ad (patch)
tree959bd861403369fc2d615104a102663a9b9a8da2 /activesupport
parentc88360ef3651702ca8f7f600e15774f51c84698b (diff)
downloadrails-fc0882ba5a0f18281736859718252042b15614ad.tar.gz
rails-fc0882ba5a0f18281736859718252042b15614ad.tar.bz2
rails-fc0882ba5a0f18281736859718252042b15614ad.zip
Optimize AS::Notifications to remember which subscribers don't match and not run them. This will allow notifications that are only useful in dev or testing to run efficiently in production.
Diffstat (limited to 'activesupport')
-rw-r--r--activesupport/lib/active_support/notifications.rb2
-rw-r--r--activesupport/lib/active_support/notifications/fanout.rb15
-rw-r--r--activesupport/test/notifications_test.rb31
3 files changed, 42 insertions, 6 deletions
diff --git a/activesupport/lib/active_support/notifications.rb b/activesupport/lib/active_support/notifications.rb
index fca2efd969..3f1fe64e9b 100644
--- a/activesupport/lib/active_support/notifications.rb
+++ b/activesupport/lib/active_support/notifications.rb
@@ -44,7 +44,7 @@ module ActiveSupport
class << self
attr_writer :notifier
- delegate :publish, :subscribe, :to => :notifier
+ delegate :publish, :subscribe, :unsubscribe, :to => :notifier
delegate :instrument, :to => :instrumenter
def notifier
diff --git a/activesupport/lib/active_support/notifications/fanout.rb b/activesupport/lib/active_support/notifications/fanout.rb
index e08011e23f..cd60054862 100644
--- a/activesupport/lib/active_support/notifications/fanout.rb
+++ b/activesupport/lib/active_support/notifications/fanout.rb
@@ -5,6 +5,7 @@ module ActiveSupport
class Fanout
def initialize
@subscribers = []
+ @listeners_for = {}
end
def bind(pattern)
@@ -12,16 +13,22 @@ module ActiveSupport
end
def subscribe(pattern = nil, &block)
+ @listeners_for.clear
@subscribers << Subscriber.new(pattern, &block)
@subscribers.last
end
def unsubscribe(subscriber)
@subscribers.delete(subscriber)
+ @listeners_for.clear
end
- def publish(*args)
- @subscribers.each { |s| s.publish(*args) }
+ def publish(name, *args)
+ if listeners = @listeners_for[name]
+ listeners.each { |s| s.publish(name, *args) }
+ else
+ @listeners_for[name] = @subscribers.select { |s| s.publish(name, *args) }
+ end
end
# This is a sync queue, so there is not waiting.
@@ -53,7 +60,9 @@ module ActiveSupport
end
def publish(*args)
- push(*args) if matches?(args.first)
+ return unless matches?(args.first)
+ push(*args)
+ true
end
def drained?
diff --git a/activesupport/test/notifications_test.rb b/activesupport/test/notifications_test.rb
index baee779b8a..67c3527e23 100644
--- a/activesupport/test/notifications_test.rb
+++ b/activesupport/test/notifications_test.rb
@@ -20,15 +20,20 @@ module Notifications
end
class UnsubscribeTest < TestCase
- def unsubscribing_removes_a_subscription
+ def test_unsubscribing_removes_a_subscription
@notifier.publish :foo
@notifier.wait
assert_equal [[:foo]], @events
@notifier.unsubscribe(@subscription)
- @notifier.publish :bar
+ @notifier.publish :foo
@notifier.wait
assert_equal [[:foo]], @events
end
+
+ private
+ def event(*args)
+ args
+ end
end
class SyncPubSubTest < TestCase
@@ -38,6 +43,28 @@ module Notifications
assert_equal [[:foo]], @events
end
+ def test_publishing_multiple_times_works
+ @notifier.publish :foo
+ @notifier.publish :foo
+ @notifier.wait
+ assert_equal [[:foo], [:foo]], @events
+ end
+
+ def test_publishing_after_a_new_subscribe_works
+ @notifier.publish :foo
+ @notifier.publish :foo
+
+ @notifier.subscribe("not_existant") do |*args|
+ @events << ActiveSupport::Notifications::Event.new(*args)
+ end
+
+ @notifier.publish :foo
+ @notifier.publish :foo
+ @notifier.wait
+
+ assert_equal [[:foo]] * 4, @events
+ end
+
def test_log_subscriber_with_pattern
events = []
@notifier.subscribe('1') { |*args| events << args }