Class: DramaQueen::Exchange

Inherits:
Object
  • Object
show all
Defined in:
lib/drama_queen/exchange.rb

Overview

An Exchange determines which objects will receive messages from a Producer. It is merely a wrapper around the routing_key that is given on initialization, allowing to more easily determine which routing_keys are related, and thus if any subscribers to the related exchanges should get notified in addition to the subscribers to this exchange.

A Exchange routing_key is what Producers and Consumers refer to when they’re looking to publish or subscribe. The Exchange routing_key can be any object, but some extra semantics & functionality come along if you use DramaQueen’s route_key globbing.

Ruby Objects

First, the simplest case: a routing_key that is any Ruby object. Producers and subscribers will use this case when observing that Ruby object. #related_exchanges will be empty; all messages published using this routing_key will only get delivered to consumers subscribing to this Exchange’s routing_key. If you only need this approach, you might be better off just using Ruby’s build-in Observer library–it accomplishes this, and is much simpler than DramaQueen.

RouteKey Globbing

Now, the fun stuff: routing key globbing uses period-delimited strings to infer some hierarchy of Exchanges. Using this approach lets you tie together other Exchanges via #related_keys, thus letting you build some organization/structure into your whole system of routing messages. These globs (somewhat similar to using Dir.glob for file systems) let your producers and consumers pub/sub to large numbers of topics, yet organize those topics. The structure that you build is up to you. Here’s a contrived example. You could use set up a routing key scheme like:

  • “my_library.bob.pants”

  • “my_library.bob.shirts”

  • “my_library.sally.pants”

  • “my_library.sally.shirts”

When producers publish to “my_library.bob.pants”, only consumers of “my_library.bob.pants” get notified. If a producer publishes to “my_library.*.pants”, consumers of both “my_library.bob.pants” and “my_library.sally.pants” get notifications. Going the other way, if a consumer subscribes to “my_library.*.pants”, then when a producer on “my_library.bob.pants”, or “my_library.sally.pants”, or “my_library.*.pants”, that consumer gets all of those messages.

Further, producers and consumers can use a single asterisk at multiple levels: “*.*.shirts” would resolve to both “my_library.bob.shirts” and “my_library.sally.shirts”; if there was a “someone_else.vendor.shirts”, for example, that would route as well.

Lastly, you can you a double-asterisk to denote that you want everything from that level and deeper. So, “**” would match all existing routing keys, including single-object (non-glob style) keys. “my_library.**” would match all four of our “my_library” keys above.

As you’re devising your routing key scheme, consider naming like you would name classes/modules in a Ruby library: use namespaces to avoid messing others up! Notice the use of “my_library…” above… that was on purpose.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(routing_key) ⇒ Exchange

Returns a new instance of Exchange.

Parameters:

  • routing_key (Object)


71
72
73
74
# File 'lib/drama_queen/exchange.rb', line 71

def initialize(routing_key)
  @routing_key = routing_key
  @subscribers = []
end

Instance Attribute Details

#routing_keyObject (readonly)

Returns:

  • (Object)


65
66
67
# File 'lib/drama_queen/exchange.rb', line 65

def routing_key
  @routing_key
end

#subscribersArray (readonly)

Returns:

  • (Array)


68
69
70
# File 'lib/drama_queen/exchange.rb', line 68

def subscribers
  @subscribers
end

Instance Method Details

#notify_with(*args) ⇒ Object

Calls each subscriber’s callback with the given arguments.

Parameters:

  • args


105
106
107
108
109
# File 'lib/drama_queen/exchange.rb', line 105

def notify_with(*args)
  @subscribers.each do |subscriber|
    subscriber.call(*args)
  end
end

All other DramaQueen::Exchange objects that the current Exchange routes to.

Returns:



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/drama_queen/exchange.rb', line 86

def related_exchanges
  return DramaQueen.exchanges if self.routing_key == '**'

  DramaQueen.exchanges.find_all do |exchange|
    next if exchange.routing_key == '**'
    next if exchange.routing_key == self.routing_key

    if self.routing_key.is_a?(String) && exchange.routing_key.is_a?(String)
      routing_key_match?(exchange.routing_key, self.routing_key) ||
        routing_key_match?(self.routing_key, exchange.routing_key)
    else
      exchange == self
    end
  end
end

#routes_to?(routing_key) ⇒ Boolean

Parameters:

  • routing_key (Object)

Returns:

  • (Boolean)


78
79
80
# File 'lib/drama_queen/exchange.rb', line 78

def routes_to?(routing_key)
  related_exchanges.include? routing_key
end