amqp 0.7.5 → 0.8.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. data/.gitignore +3 -4
  2. data/.travis.yml +3 -5
  3. data/.yardopts +6 -0
  4. data/CHANGELOG +26 -7
  5. data/Gemfile +15 -7
  6. data/README.textile +216 -0
  7. data/Rakefile +0 -6
  8. data/amqp.gemspec +14 -4
  9. data/bin/jenkins.sh +27 -0
  10. data/bin/set_test_suite_realms_up.sh +16 -2
  11. data/docs/VendorSpecificExtensions.textile +32 -0
  12. data/examples/extensions/rabbitmq/publisher_confirmations_with_transient_messages.rb +53 -0
  13. data/examples/hello_world.rb +29 -0
  14. data/examples/real-world/task-queue/README.textile +3 -0
  15. data/examples/real-world/task-queue/consumer.rb +27 -0
  16. data/examples/real-world/task-queue/producer.rb +22 -0
  17. data/examples/various/ack.rb +70 -0
  18. data/examples/various/automatic_binding_for_default_direct_exchange.rb +53 -0
  19. data/examples/various/basic_get.rb +65 -0
  20. data/examples/various/callbacks.rb +45 -0
  21. data/examples/various/clock.rb +74 -0
  22. data/examples/various/declare_a_queue_without_assignment.rb +46 -0
  23. data/examples/various/declare_an_exchange_without_assignment.rb +46 -0
  24. data/examples/various/hashtable.rb +60 -0
  25. data/examples/{logger.rb → various/logger.rb} +9 -7
  26. data/examples/{multiclock.rb → various/multiclock.rb} +15 -17
  27. data/examples/various/open_channel_without_assignment.rb +34 -0
  28. data/examples/various/pingpong.rb +53 -0
  29. data/examples/various/primes-simple.rb +29 -0
  30. data/examples/various/primes.rb +76 -0
  31. data/examples/various/pubsub.rb +43 -0
  32. data/examples/various/queue_status.rb +58 -0
  33. data/examples/various/stocks.rb +59 -0
  34. data/examples/various/weather_updates.rb +63 -0
  35. data/lib/amqp.rb +11 -2
  36. data/lib/amqp/basic_client.rb +23 -54
  37. data/lib/amqp/channel.rb +577 -805
  38. data/lib/amqp/client.rb +37 -275
  39. data/lib/amqp/connection.rb +165 -93
  40. data/lib/amqp/deprecated/fork.rb +15 -0
  41. data/lib/amqp/deprecated/logger.rb +99 -0
  42. data/lib/amqp/deprecated/mq.rb +20 -0
  43. data/lib/amqp/deprecated/rpc.rb +168 -0
  44. data/lib/amqp/exchange.rb +409 -281
  45. data/lib/amqp/extensions/rabbitmq.rb +1 -0
  46. data/lib/amqp/header.rb +41 -17
  47. data/lib/amqp/logger.rb +10 -84
  48. data/lib/amqp/queue.rb +457 -320
  49. data/lib/amqp/rpc.rb +11 -107
  50. data/lib/amqp/version.rb +1 -1
  51. data/lib/mq.rb +2 -1
  52. data/lib/mq/logger.rb +2 -0
  53. data/lib/mq/rpc.rb +2 -0
  54. data/spec/integration/authentication_spec.rb +36 -40
  55. data/spec/integration/automatic_binding_for_default_direct_exchange_spec.rb +3 -5
  56. data/spec/integration/basic_get_spec.rb +91 -0
  57. data/spec/integration/channel_close_spec.rb +5 -5
  58. data/spec/integration/exchange_declaration_spec.rb +6 -53
  59. data/spec/integration/extensions/basic_return_spec.rb +47 -0
  60. data/spec/integration/queue_declaration_spec.rb +14 -17
  61. data/spec/integration/queue_exclusivity_spec.rb +49 -48
  62. data/spec/integration/reply_queue_communication_spec.rb +6 -4
  63. data/spec/integration/store_and_forward_spec.rb +9 -36
  64. data/spec/integration/topic_subscription_spec.rb +1 -1
  65. data/spec/integration/workload_distribution_spec.rb +1 -0
  66. data/spec/spec_helper.rb +69 -43
  67. data/spec/unit/amqp/connection_spec.rb +27 -23
  68. data/tasks.rb +11 -0
  69. metadata +124 -95
  70. data/README.md +0 -156
  71. data/TODO +0 -30
  72. data/amqp.pre.gemspec +0 -6
  73. data/examples/ack.rb +0 -47
  74. data/examples/automatic_binding_for_default_direct_exchange.rb +0 -65
  75. data/examples/callbacks.rb +0 -40
  76. data/examples/clock.rb +0 -65
  77. data/examples/default_channel.rb +0 -19
  78. data/examples/hashtable.rb +0 -61
  79. data/examples/immediately_bind_a_server_named_queue.rb +0 -38
  80. data/examples/internal.rb +0 -51
  81. data/examples/issues/issue_75.rb +0 -21
  82. data/examples/issues/issue_94.rb +0 -23
  83. data/examples/pingpong.rb +0 -54
  84. data/examples/pop.rb +0 -45
  85. data/examples/primes-simple.rb +0 -21
  86. data/examples/primes.rb +0 -101
  87. data/examples/simple.rb +0 -81
  88. data/examples/stocks.rb +0 -67
  89. data/gemfiles/eventmachine-pre +0 -24
  90. data/lib/amqp/buffer.rb +0 -272
  91. data/lib/amqp/collection.rb +0 -60
  92. data/lib/amqp/frame.rb +0 -68
  93. data/lib/amqp/protocol.rb +0 -163
  94. data/lib/amqp/server.rb +0 -101
  95. data/lib/amqp/spec.rb +0 -832
  96. data/protocol/amqp-0.8.json +0 -617
  97. data/protocol/amqp-0.8.xml +0 -3908
  98. data/protocol/codegen.rb +0 -175
  99. data/protocol/doc.txt +0 -281
  100. data/research/api.rb +0 -52
  101. data/research/primes-forked.rb +0 -65
  102. data/research/primes-processes.rb +0 -137
  103. data/research/primes-threaded.rb +0 -51
  104. data/spec/integration/queue_status_spec.rb +0 -44
  105. data/spec/unit/amqp/buffer_spec.rb +0 -178
  106. data/spec/unit/amqp/client_spec.rb +0 -102
  107. data/spec/unit/amqp/collection_spec.rb +0 -144
  108. data/spec/unit/amqp/frame_spec.rb +0 -60
  109. data/spec/unit/amqp/protocol_spec.rb +0 -51
@@ -0,0 +1,15 @@
1
+ require "amqp/ext/em"
2
+
3
+ module AMQP
4
+ # @deprecated
5
+ # @api public
6
+ def self.fork(workers)
7
+ EM.fork(workers) do
8
+ # clean up globals in the fork
9
+ Thread.current[:mq] = nil
10
+ AMQP.instance_variable_set('@conn', nil)
11
+
12
+ yield
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,99 @@
1
+ # encoding: utf-8
2
+
3
+ module AMQP
4
+ class Logger
5
+ def initialize(*args, &block)
6
+ opts = args.pop if args.last.is_a? Hash
7
+ opts ||= {}
8
+
9
+ printer(block) if block
10
+
11
+ @prop = opts
12
+ @tags = ([:timestamp] + args).uniq
13
+ end
14
+
15
+ attr_reader :prop
16
+ alias :base :prop
17
+
18
+ def log(severity, *args)
19
+ opts = args.pop if args.last.is_a? Hash and args.size != 1
20
+ opts ||= {}
21
+ opts = @prop.clone.update(opts)
22
+
23
+ data = args.shift
24
+
25
+ data = {:type => :exception,
26
+ :name => data.class.to_s.intern,
27
+ :backtrace => data.backtrace,
28
+ :message => data.message} if data.is_a? Exception
29
+
30
+ (@tags + args).each do |tag|
31
+ tag = tag.to_sym
32
+ case tag
33
+ when :timestamp
34
+ opts.update :timestamp => Time.now
35
+ when :hostname
36
+ @hostname ||= { :hostname => `hostname`.strip }
37
+ opts.update @hostname
38
+ when :process
39
+ @process_id ||= { :process_id => Process.pid,
40
+ :process_name => $0,
41
+ :process_parent_id => Process.ppid,
42
+ :thread_id => Thread.current.object_id }
43
+ opts.update :process => @process_id
44
+ else
45
+ (opts[:tags] ||= []) << tag
46
+ end
47
+ end
48
+
49
+ opts.update(:severity => severity,
50
+ :msg => data)
51
+
52
+ print(opts)
53
+ unless Logger.disabled?
54
+ AMQP::Channel.new.fanout('logging', :durable => true).publish Marshal.dump(opts)
55
+ end
56
+
57
+ opts
58
+ end
59
+ alias :method_missing :log
60
+
61
+ def print(data = nil, &block)
62
+ if block
63
+ @printer = block
64
+ elsif data.is_a? Proc
65
+ @printer = data
66
+ elsif data
67
+ (pr = @printer || self.class.printer) and pr.call(data)
68
+ else
69
+ @printer
70
+ end
71
+ end
72
+ alias :printer :print
73
+
74
+ def self.printer &block
75
+ @printer = block if block
76
+ @printer
77
+ end
78
+
79
+ def self.disabled?
80
+ !!@disabled
81
+ end
82
+
83
+ def self.enable
84
+ @disabled = false
85
+ end
86
+
87
+ def self.disable
88
+ @disabled = true
89
+ end
90
+ end
91
+ end
92
+
93
+
94
+ require "amqp/deprecated/mq"
95
+ class MQ
96
+ # @note This class will be removed before 1.0 release.
97
+ # @deprecated
98
+ class Logger < ::AMQP::Logger; end
99
+ end
@@ -0,0 +1,20 @@
1
+ # Alias for AMQP::Channel.
2
+ #
3
+ # @note This class will be removed before 1.0 release.
4
+ # @deprecated
5
+ class MQ < AMQP::Channel; end
6
+
7
+
8
+ class MQ
9
+ # Alias for AMQP::Exchange.
10
+ #
11
+ # @note This class will be removed before 1.0 release.
12
+ # @deprecated
13
+ class Exchange < ::AMQP::Exchange; end
14
+
15
+ # Alias for AMQP::Queue.
16
+ #
17
+ # @note This class will be removed before 1.0 release.
18
+ # @deprecated
19
+ class Queue < ::AMQP::Queue; end
20
+ end
@@ -0,0 +1,168 @@
1
+ # encoding: utf-8
2
+
3
+ module AMQP
4
+ if defined?(BasicObject)
5
+ # @private
6
+ class BlankSlate < BasicObject; end
7
+ else
8
+ # @private
9
+ class BlankSlate
10
+ instance_methods.each { |m| undef_method m unless m =~ /^__/ }
11
+ end
12
+ end
13
+
14
+
15
+ # Basic RPC (remote procedure call) facility.
16
+ #
17
+ # Needs more detail and explanation.
18
+ #
19
+ # EM.run do
20
+ # server = AMQP::Channel.new.rpc('hash table node', Hash)
21
+ #
22
+ # client = AMQP::Channel.new.rpc('hash table node')
23
+ # client[:now] = Time.now
24
+ # client[:one] = 1
25
+ #
26
+ # client.values do |res|
27
+ # p 'client', :values => res
28
+ # end
29
+ #
30
+ # client.keys do |res|
31
+ # p 'client', :keys => res
32
+ # EM.stop_event_loop
33
+ # end
34
+ # end
35
+ #
36
+ #
37
+ # @note This class will be removed before 1.0 release.
38
+ # @deprecated
39
+ class RPC < ::AMQP::BlankSlate
40
+
41
+ #
42
+ # API
43
+ #
44
+
45
+
46
+ attr_reader :name
47
+
48
+ # Takes a channel, queue and optional object.
49
+ #
50
+ # The optional object may be a class name, module name or object
51
+ # instance. When given a class or module name, the object is instantiated
52
+ # during this setup. The passed queue is automatically subscribed to so
53
+ # it passes all messages (and their arguments) to the object.
54
+ #
55
+ # Marshalling and unmarshalling the objects is handled internally. This
56
+ # marshalling is subject to the same restrictions as defined in the
57
+ # {http://ruby-doc.org/core/classes/Marshal.html Marshal} standard
58
+ # library. See that documentation for further reference.
59
+ #
60
+ # When the optional object is not passed, the returned rpc reference is
61
+ # used to send messages and arguments to the queue. See #method_missing
62
+ # which does all of the heavy lifting with the proxy. Some client
63
+ # elsewhere must call this method *with* the optional block so that
64
+ # there is a valid destination. Failure to do so will just enqueue
65
+ # marshalled messages that are never consumed.
66
+ #
67
+ def initialize(channel, queue, obj = nil)
68
+ @name = queue
69
+ @channel = channel
70
+ @channel.register_rpc(self)
71
+
72
+ if @obj = normalize(obj)
73
+ @delegate = Server.new(channel, queue, @obj)
74
+ else
75
+ @delegate = Client.new(channel, queue)
76
+ end
77
+ end
78
+
79
+
80
+ def client?
81
+ @obj.nil?
82
+ end
83
+
84
+ def server?
85
+ !client?
86
+ end
87
+
88
+
89
+ def method_missing(selector, *args, &block)
90
+ @delegate.__send__(selector, *args, &block)
91
+ end
92
+
93
+
94
+ # @private
95
+ class Client
96
+ attr_accessor :identifier
97
+
98
+ def initialize(channel, server_queue_name)
99
+ @channel = channel
100
+ @exchange = AMQP::Exchange.default(@channel)
101
+ @server_queue_name = server_queue_name
102
+
103
+ @handlers = Hash.new
104
+ @queue = channel.queue("__amqp_gem_rpc_client_#{rand(1_000_000)}", :auto_delete => true)
105
+
106
+ @queue.subscribe do |header, payload|
107
+ *response_args = Marshal.load(payload)
108
+ handler = @handlers[header.message_id]
109
+
110
+ handler.call(*response_args)
111
+ end
112
+ end
113
+
114
+ def method_missing(selector, *args, &block)
115
+ @channel.once_open do
116
+ message_id = "message_identifier_#{rand(1_000_000)}"
117
+
118
+ if block
119
+ @handlers[message_id] = block
120
+ @exchange.publish(Marshal.dump([selector, *args]), :routing_key => @server_queue_name, :reply_to => @queue.name, :message_id => message_id)
121
+ else
122
+ @exchange.publish(Marshal.dump([selector, *args]), :routing_key => @server_queue_name, :message_id => message_id)
123
+ end
124
+ end
125
+ end
126
+ end # Client
127
+
128
+ # @private
129
+ class Server
130
+ def initialize(channel, queue_name, impl)
131
+ @channel = channel
132
+ @exchange = AMQP::Exchange.default(@channel)
133
+ @queue = @channel.queue(queue_name)
134
+ @impl = impl
135
+
136
+ @handlers = Hash.new
137
+ @id = "client_identifier_#{rand(1_000_000)}"
138
+
139
+ @queue.subscribe(:ack => true) do |header, payload|
140
+ selector, *args = Marshal.load(payload)
141
+ result = @impl.__send__(selector, *args)
142
+
143
+ respond_to(header, result) if header.to_hash[:reply_to]
144
+ header.ack
145
+ end
146
+ end
147
+
148
+ def respond_to(header, result)
149
+ @exchange.publish(Marshal.dump(result), :message_id => header.message_id, :routing_key => header.reply_to)
150
+ end
151
+ end # Server
152
+
153
+
154
+
155
+ protected
156
+
157
+ def normalize(input)
158
+ case input
159
+ when ::Class
160
+ input.new
161
+ when ::Module
162
+ (::Class.new do include(obj) end).new
163
+ else
164
+ input
165
+ end
166
+ end
167
+ end # RPC
168
+ end # AMQP
@@ -1,13 +1,43 @@
1
1
  # encoding: utf-8
2
2
 
3
+ require "amq/client/exchange"
4
+
3
5
  module AMQP
4
- # An Exchange acts as an ingress point for all published messages. An
6
+
7
+ # h2. What are AMQP exchanges?
8
+ #
9
+ # AMQP exchange is where AMQP clients send messages. AMQP
5
10
  # exchange may also be described as a router or a matcher. Every
6
11
  # published message is received by an exchange which, depending on its
7
- # type (described below), determines how to deliver the message.
12
+ # type and message attributes, determines how to deliver the message.
13
+ #
14
+ #
15
+ # h2. Exchange types
16
+ #
17
+ # There are 4 supported exchange types: direct, fanout, topic and headers.
18
+ #
19
+ # As part of the standard, the server _must_ predeclare the direct exchange
20
+ # 'amq.direct' and the fanout exchange 'amq.fanout'. All exchange names
21
+ # starting with 'amq.' are reserved: attempts to declare an exchange using
22
+ # 'amq.' as the name will raise an AMQP::Error and fail.
8
23
  #
9
- # It determines the next delivery hop by examining the bindings associated
10
- # with the exchange.
24
+ # Note that durability of exchanges and durability of messages published to exchanges
25
+ # are different concepts. Sending messages to durable exchanges does not make
26
+ # messages themselves persistent.
27
+ #
28
+ #
29
+ # h2. AMQP bindings
30
+ #
31
+ # Closely related to exchange is a concept of bindings. A binding is
32
+ # the relationship between an exchange and a message queue that tells
33
+ # the exchange how to route messages. Bindings are set up by
34
+ # AMQP applications (usually the app owning and using the message queue
35
+ # sets up bindings for it). Exchange may be bound to none, 1 or more than 1
36
+ # queue.
37
+ #
38
+ #
39
+ # Defines, intializes and returns an Exchange to act as an ingress
40
+ # point for all published messages.
11
41
  #
12
42
  # There are three (3) supported Exchange types: direct, fanout and topic.
13
43
  #
@@ -17,222 +47,292 @@ module AMQP
17
47
  # 'amq.' as the name will raise an AMQP::Error and fail. In practice these
18
48
  # default exchanges are never used directly by client code.
19
49
  #
20
- # These predececlared exchanges are used when the client code declares
21
- # an exchange without a name. In these cases the library will use
22
- # the default exchange for publishing the messages.
23
50
  #
24
- class Exchange
51
+ # h2. Direct exchanges
52
+ #
53
+ # Direct exchanges are useful for 1:1 communication scenarios.
54
+ # Queues are bound to direct exchanges with a parameter called "routing key". When messages
55
+ # arrive to a direct exchange, broker takes that message's routing key (if any), finds a queue bound
56
+ # to the exchange with the same routing key and routes message there.
57
+ #
58
+ # Because very often queues are bound with the same routing key as queue's name, AMQP 0.9.1 has
59
+ # a pre-declared direct exchange known as default exchange. Default exchange is a bit special: broker
60
+ # automatically binds all the queues (in the same virtual host) to it with routing key equal to
61
+ # queue names. In other words, messages delivered to default exchange are routed to queues when
62
+ # message routing key equals queue name. Default exchange name is an empty string.
63
+ #
64
+ #
65
+ #
66
+ # h2. Fanout exchanges
67
+ #
68
+ # Fanout exchanges are useful for 1:n and n:m communication where one or more producer
69
+ # feeds multiple consumers. messages published
70
+ # to a fanout exchange are delivered to queues that are bound to that exchange name (unconditionally).
71
+ # Each queue gets it's own copy of the message.
72
+ #
73
+ #
74
+ #
75
+ # h2. Topic exchanges
76
+ #
77
+ # Topic exchanges are used for 1:n and n:m communication scenarios.
78
+ # Exchange of this type uses the routing key
79
+ # to determine which queues to deliver the message. Wildcard matching
80
+ # is allowed. The topic must be declared using dot notation to separate
81
+ # each subtopic.
82
+ #
83
+ # As part of the AMQP standard, each server _should_ predeclare a topic
84
+ # exchange called 'amq.topic'.
85
+ #
86
+ # The classic example is delivering market data. When publishing market
87
+ # data for stocks, we may subdivide the stream based on 2
88
+ # characteristics: nation code and trading symbol. The topic tree for
89
+ # Apple may look like stock.us.aapl. NASDAQ updates may use topic stocks.us.nasdaq,
90
+ # while DAX may use stock.de.dax.
91
+ #
92
+ # When publishing data to the exchange, bound queues subscribing to the
93
+ # exchange indicate which data interests them by passing a routing key
94
+ # for matching against the published routing key.
95
+ #
96
+ #
97
+ # h2. Headers exchanges
98
+ #
99
+ # As part of the AMQP standard, each server _should_ predeclare a headers
100
+ # exchange named 'amq.match'.
101
+ #
102
+ # When publishing data to the exchange, bound queues subscribing to the
103
+ # exchange indicate which data interests them by passing arguments
104
+ # for matching against the headers in published messages. The
105
+ # form of the matching can be controlled by the 'x-match' argument, which
106
+ # may be 'any' or 'all'. If unspecified, it defaults to "all".
107
+ #
108
+ # A value of 'all' for 'x-match' implies that all values must match (i.e.
109
+ # it does an AND of the headers ), while a value of 'any' implies that
110
+ # at least one should match (ie. it does an OR).
111
+ #
112
+ #
113
+ # h2. Exchange durability and persistence of messages.
114
+ #
115
+ # AMQP separates concept of durability of entities (queues, exchanges) from messages persistence.
116
+ # Exchanges can be durable or transient. Durable exchanges survive broker restart, transient exchanges don't (they
117
+ # have to be redeclared when broker comes back online). Not all scenarios and use cases mandate exchanges to be
118
+ # durable.
119
+ #
120
+ # The concept of messages persistence is separate: messages may be published as persistent. That makes
121
+ # AMQP broker persist them to disk. If the server is restarted, the system ensures that received persistent messages
122
+ # are not lost. Simply publishing message to a durable exchange or the fact that queue(s) they are routed to
123
+ # is durable doesn't make messages persistent: it all depends on persistence mode of the messages itself.
124
+ # Publishing messages as persistent affects performance (just like with data stores, durability comes at a certain cost
125
+ # in performance and vise versa). Pass :persistent => true to {Exchange#publish} to publish your message as persistent.
126
+ #
127
+ # Note that *only durable queues can be bound to durable exchanges*.
128
+ #
129
+ #
130
+ # h2. RabbitMQ extensions.
131
+ #
132
+ # AMQP gem supports several RabbitMQ extensions taht extend Exchange functionality.
133
+ # Learn more in {file:docs/VendorSpecificExtensions.textile}
134
+ #
135
+ #
136
+ # h2. Key methods
137
+ #
138
+ # Key methods of Exchange class are
139
+ #
140
+ # * {Exchange#publish}
141
+ # * {Exchange#delete}
142
+ # * {Exchange.default}
143
+ #
144
+ #
145
+ # @note Please make sure you read a section on exchanges durability vs. messages
146
+ # persistence.
147
+ #
148
+ # @see http://www.rabbitmq.com/faq.html#managing-concepts-exchanges Exchanges explained in the RabbitMQ FAQ
149
+ # @see http://www.rabbitmq.com/faq.html#Binding-and-Routing Bindings and routing explained in the RabbitMQ FAQ
150
+ # @see Channel#default_exchange
151
+ # @see Channel#direct
152
+ # @see Channel#fanout
153
+ # @see Channel#topic
154
+ # @see Channel#headers
155
+ # @see Queue
156
+ # @see http://bit.ly/hw2ELX AMQP 0.9.1 specification (Section 2.1.1)
157
+ # @see http://bit.ly/hw2ELX AMQP 0.9.1 specification (Section 2.1.5)
158
+ # @see http://bit.ly/hw2ELX AMQP 0.9.1 specification (Section 3.1.3)
159
+ class Exchange < AMQ::Client::Exchange
25
160
 
26
161
  #
27
162
  # API
28
163
  #
29
164
 
165
+ DEFAULT_CONTENT_TYPE = "application/octet-stream".freeze
30
166
 
31
- # The default exchange.
32
- # Every queue is bind to this (direct) exchange by default.
33
- # You can't remove it or bind there queue explicitly.
34
-
35
- # Do NOT confuse with amq.direct: it's only a normal direct
36
- # exchange and the only special thing about it is that it's
37
- # predefined in the system, so you can use it straightaway.
38
167
 
39
- # Example:
40
- # AMQP::Channel.new.queue("tasks")
41
- # AMQP::Channel::Exchange.default.publish("make clean", routing_key: "tasks")
42
-
43
- # For more info see section 2.1.2.4 Automatic Mode of the AMQP 0.9.1 spec.
168
+ # The default exchange. Default exchange is a direct exchange that is predefined.
169
+ # It cannot be removed. Every queue is bind to this (direct) exchange by default with
170
+ # the following routing semantics: messages will be routed to the queue withe same
171
+ # same name as message's routing key. In other words, if a message is published with
172
+ # a routing key of "weather.usa.ca.sandiego" and there is a queue Q with this name,
173
+ # that message will be routed to Q.
174
+ #
175
+ # @param [AMQP::Channel] channel Channel to use. If not given, new AMQP channel
176
+ # will be opened on the default AMQP connection (accessible as AMQP.connection).
177
+ #
178
+ # @example Publishing a messages to the tasks queue
179
+ # channel = AMQP::Channel.new(connection)
180
+ # tasks_queue = channel.queue("tasks")
181
+ # AMQP::Exchange.default(channel).publish("make clean", routing_key => "tasks")
182
+ #
183
+ # @see Exchange
184
+ # @see http://bit.ly/hw2ELX AMQP 0.9.1 specification (Section 2.1.2.4)
185
+ # @note Do not confuse default exchange with amq.direct: amq.direct is a pre-defined direct
186
+ # exchange that doesn't have any special routing semantics.
187
+ # @return [Exchange] An instance that corresponds to the default exchange (of type direct).
188
+ # @api public
44
189
  def self.default(channel = nil)
45
- self.new(channel || AMQP::Channel.new, :direct, "", :no_declare => true)
190
+ self.new(channel || AMQP::Channel.new, :direct, AMQ::Protocol::EMPTY_STRING, :no_declare => true)
46
191
  end
47
192
 
48
- def self.add_default_options(type, name, opts, block)
49
- { :exchange => name, :type => type, :nowait => block.nil? }.merge(opts)
193
+
194
+ # @return [String]
195
+ attr_reader :name
196
+
197
+ # Type of this exchange (one of: :direct, :fanout, :topic, :headers).
198
+ # @return [Symbol]
199
+ attr_reader :type
200
+
201
+ # @return [Symbol]
202
+ # @api plugin
203
+ attr_reader :status
204
+
205
+ # Options hash this exchange instance was instantiated with
206
+ # @return [Hash]
207
+ attr_accessor :opts
208
+
209
+ # @return [#call] A callback that is executed once declaration notification (exchange.declare-ok)
210
+ # from the broker arrives.
211
+ attr_accessor :on_declare
212
+
213
+ # @return [String]
214
+ attr_reader :default_routing_key
215
+ alias key default_routing_key
216
+
217
+ # Compatibility alias for #on_declare.
218
+ #
219
+ # @api public
220
+ # @deprecated
221
+ # @return [#call]
222
+ def callback
223
+ @on_declare
50
224
  end
51
225
 
52
- # Defines, intializes and returns an Exchange to act as an ingress
53
- # point for all published messages.
54
- #
55
- # There are three (3) supported Exchange types: direct, fanout and topic.
56
- #
57
- # As part of the standard, the server _must_ predeclare the direct exchange
58
- # 'amq.direct' and the fanout exchange 'amq.fanout' (all exchange names
59
- # starting with 'amq.' are reserved). Attempts to declare an exchange using
60
- # 'amq.' as the name will raise an AMQP::Error and fail. In practice these
61
- # default exchanges are never used directly by client code.
62
- #
63
- # == Direct
64
- # A direct exchange is useful for 1:1 communication between a publisher and
65
- # subscriber. Messages are routed to the queue with a binding that shares
66
- # the same name as the exchange. Alternately, the messages are routed to
67
- # the bound queue that shares the same name as the routing key used for
68
- # defining the exchange. This exchange type does not honor the :key option
69
- # when defining a new instance with a name. It _will_ honor the :key option
70
- # if the exchange name is the empty string. This is because an exchange
71
- # defined with the empty string uses the default pre-declared exchange
72
- # called 'amq.direct'. In this case it needs to use :key to do its matching.
73
- #
74
- # # exchange is named 'foo'
75
- # exchange = AMQP::Channel::Exchange.new(AMQP::Channel.new, :direct, 'foo')
76
- #
77
- # # or, the exchange can use the default name (amq.direct) and perform
78
- # # routing comparisons using the :key
79
- # exchange = AMQP::Channel::Exchange.new(AMQP::Channel.new, :direct, "", :key => 'foo')
80
- # exchange.publish('some data') # will be delivered to queue bound to 'foo'
81
- #
82
- # queue = AMQP::Channel::Queue.new(AMQP::Channel.new, 'foo')
83
- # # can receive data since the queue name and the exchange key match exactly
84
- # queue.pop { |data| puts "received data [#{data}]" }
85
- #
86
- # == Fanout
87
- # A fanout exchange is useful for 1:N communication where one publisher
88
- # feeds multiple subscribers. Like direct exchanges, messages published
89
- # to a fanout exchange are delivered to queues whose name matches the
90
- # exchange name (or are bound to that exchange name). Each queue gets
91
- # its own copy of the message.
92
- #
93
- # Like the direct exchange type, this exchange type does not honor the
94
- # :key option when defining a new instance with a name. It _will_ honor
95
- # the :key option if the exchange name is the empty string. Fanout exchanges
96
- # defined with the empty string as the name use the default 'amq.fanout'.
97
- # In this case it needs to use :key to do its matching.
98
- #
99
- # EM.run do
100
- # clock = AMQP::Channel::Exchange.new(AMQP::Channel.new, :fanout, 'clock')
101
- # EM.add_periodic_timer(1) do
102
- # puts "\npublishing #{time = Time.now}"
103
- # clock.publish(Marshal.dump(time))
104
- # end
105
- #
106
- # # one way of defining a queue
107
- # amq = AMQP::Channel::Queue.new(AMQP::Channel.new, 'every second')
108
- # amq.bind(AMQP::Channel.fanout('clock')).subscribe do |time|
109
- # puts "every second received #{Marshal.load(time)}"
110
- # end
111
- #
112
- # # defining a queue using the convenience method
113
- # # note the string passed to #bind
114
- # AMQP::Channel.queue('every 5 seconds').bind('clock').subscribe do |time|
115
- # time = Marshal.load(time)
116
- # puts "every 5 seconds received #{time}" if time.strftime('%S').to_i%5 == 0
117
- # end
118
- # end
119
- #
120
- # == Topic
121
- # A topic exchange allows for messages to be published to an exchange
122
- # tagged with a specific routing key. The Exchange uses the routing key
123
- # to determine which queues to deliver the message. Wildcard matching
124
- # is allowed. The topic must be declared using dot notation to separate
125
- # each subtopic.
126
- #
127
- # This is the only exchange type to honor the :key parameter.
128
- #
129
- # As part of the AMQP standard, each server _should_ predeclare a topic
130
- # exchange called 'amq.topic' (this is not required by the standard).
131
- #
132
- # The classic example is delivering market data. When publishing market
133
- # data for stocks, we may subdivide the stream based on 2
134
- # characteristics: nation code and trading symbol. The topic tree for
135
- # Apple Computer would look like:
136
- # 'stock.us.aapl'
137
- # For a foreign stock, it may look like:
138
- # 'stock.de.dax'
139
- #
140
- # When publishing data to the exchange, bound queues subscribing to the
141
- # exchange indicate which data interests them by passing a routing key
142
- # for matching against the published routing key.
143
- #
144
- # EM.run do
145
- # exch = AMQP::Channel::Exchange.new(AMQP::Channel.new, :topic, "stocks")
146
- # keys = ['stock.us.aapl', 'stock.de.dax']
147
- #
148
- # EM.add_periodic_timer(1) do # every second
149
- # puts
150
- # exch.publish(10+rand(10), :routing_key => keys[rand(2)])
151
- # end
152
- #
153
- # # match against one dot-separated item
154
- # AMQP::Channel.queue('us stocks').bind(exch, :key => 'stock.us.*').subscribe do |price|
155
- # puts "us stock price [#{price}]"
156
- # end
157
- #
158
- # # match against multiple dot-separated items
159
- # AMQP::Channel.queue('all stocks').bind(exch, :key => 'stock.#').subscribe do |price|
160
- # puts "all stocks: price [#{price}]"
161
- # end
162
- #
163
- # # require exact match
164
- # AMQP::Channel.queue('only dax').bind(exch, :key => 'stock.de.dax').subscribe do |price|
165
- # puts "dax price [#{price}]"
166
- # end
167
- # end
168
- #
169
- # For matching, the '*' (asterisk) wildcard matches against one
170
- # dot-separated item only. The '#' wildcard (hash or pound symbol)
171
- # matches against 0 or more dot-separated items. If none of these
172
- # symbols are used, the exchange performs a comparison looking for an
173
- # exact match.
226
+
227
+
228
+ # See {Exchange Exchange class documentation} for introduction, information about exchange types,
229
+ # what uses cases they are good for and so on.
174
230
  #
175
- # == Options
176
- # * :passive => true | false (default false)
177
- # If set, the server will not create the exchange if it does not
178
- # already exist. The client can use this to check whether an exchange
179
- # exists without modifying the server state.
180
- #
181
- # * :durable => true | false (default false)
182
- # If set when creating a new exchange, the exchange will be marked as
183
- # durable. Durable exchanges remain active when a server restarts.
184
- # Non-durable exchanges (transient exchanges) are purged if/when a
185
- # server restarts.
186
- #
187
- # A transient exchange (the default) is stored in memory-only
188
- # therefore it is a good choice for high-performance and low-latency
189
- # message publishing.
190
- #
191
- # Durable exchanges cause all messages to be written to non-volatile
192
- # backing store (i.e. disk) prior to routing to any bound queues.
193
- #
194
- # * :auto_delete => true | false (default false)
195
- # If set, the exchange is deleted when all queues have finished
196
- # using it. The server waits for a short period of time before
197
- # determining the exchange is unused to give time to the client code
198
- # to bind a queue to it.
199
- #
200
- # If the exchange has been previously declared, this option is ignored
201
- # on subsequent declarations.
202
- #
203
- # * :internal => true | false (default false)
204
- # If set, the exchange may not be used directly by publishers, but
205
- # only when bound to other exchanges. Internal exchanges are used to
206
- # construct wiring that is not visible to applications.
231
+ # h2. Predeclared exchanges
207
232
  #
208
- # * :nowait => true | false (default true)
209
- # If set, the server will not respond to the method. The client should
210
- # not wait for a reply method. If the server could not complete the
211
- # method it will raise a channel or connection exception.
233
+ # If exchange name corresponds to one of those predeclared by AMQP 0.9.1 specification (empty string, amq.direct, amq.fanout, amq.topic, amq.match),
234
+ # declaration command won't be sent to the broker (because the only possible reply from the broker is to reject it, predefined entities cannot be changed).
235
+ # Callback, if any, will be executed immediately.
236
+ #
237
+ #
238
+ #
239
+ # @example Instantiating a fanout exchange using constructor
240
+ #
241
+ # AMQP.connect do |connection|
242
+ # AMQP::Channel.new(connection) do |channel|
243
+ # AMQP::Exchange.new(channel, :fanout, "search.index.updates") do |exchange, declare_ok|
244
+ # # by now exchange is ready and waiting
245
+ # end
246
+ # end
247
+ # end
248
+ #
249
+ #
250
+ # @example Instantiating a direct exchange using {Channel#direct}
251
+ #
252
+ # AMQP.connect do |connection|
253
+ # AMQP::Channel.new(connection) do |channel|
254
+ # channel.direct("email.replies_listener") do |exchange, declare_ok|
255
+ # # by now exchange is ready and waiting
256
+ # end
257
+ # end
258
+ # end
259
+ #
260
+ #
261
+ # @param [Channel] channel AMQP channel this exchange is associated with
262
+ # @param [Symbol] type Exchange type
263
+ # @param [String] name Exchange name
212
264
  #
213
- # * :no_declare => true | false (default false)
214
- # If set, the exchange will not be declared to the
215
- # AMQP broker at instantiation-time. This allows the AMQP
216
- # client to send messages to exchanges that were
217
- # already declared by someone else, e.g. if the client
218
- # does not have sufficient privilege to declare (create)
219
- # an exchange. Use with caution, as binding to an exchange
220
- # with the no-declare option causes your system to become
221
- # sensitive to the ordering of clients' actions!
222
- #
223
- # == Exceptions
224
- # Doing any of these activities are illegal and will raise exceptions:
225
- #
226
- # * redeclare an already-declared exchange to a different type (raises AMQP::Channel::IncompatibleOptionsError)
227
- # * :passive => true and the exchange does not exist (NOT_FOUND)
228
- #
229
- def initialize(mq, type, name, opts = {}, &block)
230
- @mq = mq
231
- @type, @opts = type, opts
232
- @opts = self.class.add_default_options(type, name, opts, block)
233
- @key = opts[:key]
234
- @name = name unless name.empty?
235
- @status = :unknown
265
+ #
266
+ # @option opts [Boolean] :passive (false) If set, the server will not create the exchange if it does not
267
+ # already exist. The client can use this to check whether an exchange
268
+ # exists without modifying the server state.
269
+ #
270
+ # @option opts [Boolean] :durable (false) If set when creating a new exchange, the exchange will be marked as
271
+ # durable. Durable exchanges and their bindings are recreated upon a server
272
+ # restart (information about them is persisted). Non-durable (transient) exchanges
273
+ # do not survive if/when a server restarts (information about them is stored exclusively
274
+ # in RAM).
275
+ #
276
+ #
277
+ # @option opts [Boolean] :auto_delete (false) If set, the exchange is deleted when all queues have finished
278
+ # using it. The server waits for a short period of time before
279
+ # determining the exchange is unused to give time to the client code
280
+ # to bind a queue to it.
281
+ #
282
+ # @option opts [Boolean] :internal (false) If set, the exchange may not be used directly by publishers, but
283
+ # only when bound to other exchanges. Internal exchanges are used to
284
+ # construct wiring that is not visible to applications. *This is a RabbitMQ-specific
285
+ # extension.*
286
+ #
287
+ # @option opts [Boolean] :nowait (true) If set, the server will not respond to the method. The client should
288
+ # not wait for a reply method. If the server could not complete the
289
+ # method it will raise a channel or connection exception.
290
+ #
291
+ # @option opts [Boolean] :no_declare (true) If set, exchange declaration command won't be sent to the broker. Allows to forcefully
292
+ # avoid declaration. We recommend that only experienced developers consider this option.
293
+ #
294
+ # @option opts [String] :default_routing_key (nil) Default routing key that will be used by {Exchange#publish} when no routing key is not passed explicitly.
295
+ # It is perfectly fine for applications to always specify routing key to {Exchange#publish}.
296
+ #
297
+ #
298
+ # @raise [AMQP::Error] Raised when exchange is redeclared with parameters different from original declaration.
299
+ # @raise [AMQP::Error] Raised when exchange is declared with :passive => true and the exchange does not exist.
300
+ #
301
+ # @yield [exchange, declare_ok] Yields successfully declared exchange instance and AMQP method (exchange.declare-ok) instance. The latter is optional.
302
+ # @yieldparam [Exchange] exchange Exchange that is successfully declared and is ready to be used.
303
+ # @yieldparam [AMQP::Protocol::Exchange::DeclareOk] declare_ok AMQP exchange.declare-ok) instance.
304
+ #
305
+ # @see Channel#default_exchange
306
+ # @see Channel#direct
307
+ # @see Channel#fanout
308
+ # @see Channel#topic
309
+ # @see Channel#headers
310
+ # @see Queue
311
+ # @see http://bit.ly/hw2ELX AMQP 0.9.1 specification (Section 3.1.3)
312
+ #
313
+ # @return [Exchange]
314
+ # @api public
315
+ def initialize(channel, type, name, opts = {}, &block)
316
+ @channel = channel
317
+ @type = type
318
+ @opts = self.class.add_default_options(type, name, opts, block)
319
+ @default_routing_key = opts[:routing_key] || opts[:key]
320
+ @name = name unless name.empty?
321
+
322
+ @status = :unknown
323
+ @default_publish_options = (opts.delete(:default_publish_options) || {
324
+ :routing_key => AMQ::Protocol::EMPTY_STRING,
325
+ :mandatory => false,
326
+ :immediate => false
327
+ }).freeze
328
+
329
+ @default_headers = (opts.delete(:default_headers) || {
330
+ :content_type => DEFAULT_CONTENT_TYPE,
331
+ :persistent => false,
332
+ :priority => 0
333
+ }).freeze
334
+
335
+ super(channel.connection, channel, name, type)
236
336
 
237
337
  # The AMQP 0.8 specification (as well as 0.9.1) in 1.1.4.2 mentiones
238
338
  # that Exchange.Declare-Ok confirms the name of the exchange (because
@@ -244,98 +344,118 @@ module AMQP
244
344
  # or nameless exchange), so if we'd send Exchange.Declare(exchange=""),
245
345
  # then RabbitMQ interpret it as if we'd try to redefine this default
246
346
  # exchange so it'd produce an error.
247
- unless name == "amq.#{type}" or name == '' or opts[:no_declare]
248
- @status = :unfinished
249
- @mq.callback {
250
- @mq.send Protocol::Exchange::Declare.new(@opts)
251
- }
347
+ unless name == "amq.#{type}" or name.empty? or opts[:no_declare]
348
+ @status = :opening
349
+
350
+ shim = Proc.new do |exchange, declare_ok|
351
+ case block.arity
352
+ when 1 then block.call(exchange)
353
+ else
354
+ block.call(exchange, declare_ok)
355
+ end
356
+ end
357
+
358
+ unless @opts[:no_declare]
359
+ @channel.once_open do
360
+ self.declare(passive = @opts[:passive], durable = @opts[:durable], exclusive = @opts[:exclusive], auto_delete = @opts[:auto_delete], nowait = @opts[:nowait], nil, &shim)
361
+ end
362
+ end
252
363
  else
253
364
  # Call the callback immediately, as given exchange is already
254
365
  # declared.
255
- @status = :finished
366
+ @status = :opened
256
367
  block.call(self) if block
257
368
  end
258
369
 
259
- self.callback = block
370
+ @on_declare = block
260
371
  end
261
372
 
262
- attr_reader :name, :type, :key, :status
263
- attr_accessor :opts, :callback
264
-
373
+ # @return [Channel]
374
+ # @api public
265
375
  def channel
266
- @mq
267
- end # channel
376
+ @channel
377
+ end
268
378
 
269
- # This method publishes a staged file message to a specific exchange.
270
- # The file message will be routed to queues as defined by the exchange
271
- # configuration and distributed to any active consumers when the
272
- # transaction, if any, is committed.
379
+ # Publishes message to the exchange. The message will be routed to queues by the exchange
380
+ # and distributed to any active consumers. Routing logic is determined by exchange type and
381
+ # configuration as well as message attributes (like :routing_key).
273
382
  #
274
- # exchange = AMQP::Channel.direct('name', :key => 'foo.bar')
275
- # exchange.publish("some data")
383
+ # h2. Data serialization
276
384
  #
277
- # The method takes several hash key options which modify the behavior or
278
- # lifecycle of the message.
385
+ # Note that this method calls #to_s on payload argument value. You are encouraged to take care of
386
+ # data serialization before publishing (using JSON, Thrift, Protocol Buffers or other serialization library).
387
+ # Note that because AMQP is a binary protocol, text formats like JSON lose lose their strong point of being easy
388
+ # to inspect data as it travels across network.
279
389
  #
280
- # * :routing_key => 'string'
281
390
  #
282
- # Specifies the routing key for the message. The routing key is
283
- # used for routing messages depending on the exchange configuration.
284
391
  #
285
- # * :mandatory => true | false (default false)
392
+ # h2. Event loop blocking
286
393
  #
287
- # This flag tells the server how to react if the message cannot be
288
- # routed to a queue. If this flag is set, the server will return an
289
- # unroutable message with a Return method. If this flag is zero, the
290
- # server silently drops the message.
394
+ # To minimize blocking of EventMachine event loop, this method performs network I/O on the next event loop tick.
291
395
  #
292
- # * :immediate => true | false (default false)
396
+ # @param [#to_s] payload Message payload (content). Note that this method calls #to_s on payload argument value.
397
+ # You are encouraged to take care of data serialization before publishing (using JSON, Thrift,
398
+ # Protocol Buffers or other serialization library).
293
399
  #
294
- # This flag tells the server how to react if the message cannot be
295
- # routed to a queue consumer immediately. If this flag is set, the
296
- # server will return an undeliverable message with a Return method.
297
- # If this flag is zero, the server will queue the message, but with
298
- # no guarantee that it will ever be consumed.
400
+ # @option options [String] :routing_key (nil) Specifies message routing key. Routing key determines
401
+ # what queues messages are delivered to (exact routing algorithms vary
402
+ # between exchange types).
299
403
  #
300
- # * :persistent
301
- # True or False. When true, this message will remain in the queue until
302
- # it is consumed (if the queue is durable). When false, the message is
303
- # lost if the server restarts and the queue is recreated.
404
+ # @option options [Boolean] :mandatory (false) This flag tells the server how to react if the message cannot be
405
+ # routed to a queue. If message is mandatory, the server will return
406
+ # unroutable message back to the client with basic.return AMQPmethod.
407
+ # If message is not mandatory, the server silently drops the message.
304
408
  #
305
- # For high-performance and low-latency, set :persistent => false so the
306
- # message stays in memory and is never persisted to non-volatile (slow)
307
- # storage.
409
+ # @option options [Boolean] :immediate (false) This flag tells the server how to react if the message cannot be
410
+ # routed to a queue consumer immediately. If this flag is set, the
411
+ # server will return an undeliverable message with a Return method.
412
+ # If this flag is zero, the server will queue the message, but with
413
+ # no guarantee that it will ever be consumed.
308
414
  #
309
- # * :content_type
310
- # Content type you want to send the message with. It defaults to "application/octet-stream".
311
- def publish(data, opts = {})
312
- @mq.callback {
313
- out = []
314
-
315
- out << Protocol::Basic::Publish.new({ :exchange => name,
316
- :routing_key => opts[:key] || @key }.merge(opts))
317
-
318
- data = data.to_s
319
-
320
- out << Protocol::Header.new(Protocol::Basic,
321
- data.bytesize, { opts[:content_type] || :content_type => "application/octet-stream",
322
- :delivery_mode => (opts[:persistent] ? 2 : 1),
323
- :priority => 0 }.merge(opts))
415
+ # @option options [Boolean] :persistent (false) When true, this message will be persisted to disk and remain in the queue until
416
+ # it is consumed. When false, the message is only kept in a transient store
417
+ # and will lost in case of server restart.
418
+ # When performance and latency are more important than durability, set :persistent => false.
419
+ # If durability is more important, set :persistent => true.
420
+ #
421
+ # @option options [String] :content_type (application/octet-stream) Content-type of message payload.
422
+ #
423
+ #
424
+ # @example Publishing without routing key
425
+ # exchange = channel.fanout('search.indexer')
426
+ # # fanout exchanges deliver messages to bound queues unconditionally,
427
+ # # so routing key is unnecessary here
428
+ # exchange.publish("some data")
429
+ #
430
+ # @example Publishing with a routing key
431
+ # exchange = channel.direct('search.indexer')
432
+ # exchange.publish("some data", :routing_key => "search.index.updates")
433
+ #
434
+ # @return [Exchange] self
435
+ #
436
+ # @note Please make sure you read {Exchange Exchange class} documentation section on exchanges durability vs. messages
437
+ # persistence.
438
+ # @api public
439
+ def publish(payload, options = {}, &block)
440
+ EM.next_tick do
441
+ opts = @default_publish_options.merge(options)
324
442
 
325
- out << Frame::Body.new(data)
443
+ @channel.once_open do
444
+ super(payload.to_s, opts[:key] || opts[:routing_key] || @default_routing_key, @default_headers.merge(options), opts[:mandatory], opts[:immediate], &block)
445
+ end
446
+ end
326
447
 
327
- @mq.send *out
328
- }
329
448
  self
330
449
  end
331
450
 
451
+
332
452
  # This method deletes an exchange. When an exchange is deleted all queue
333
453
  # bindings on the exchange are cancelled.
334
454
  #
335
455
  # Further attempts to publish messages to a deleted exchange will raise
336
456
  # an AMQP::Channel::Error due to a channel close exception.
337
457
  #
338
- # exchange = AMQP::Channel.direct('name', :key => 'foo.bar')
458
+ # exchange = AMQP::Channel.direct('name', :routing_key => 'foo.bar')
339
459
  # exchange.delete
340
460
  #
341
461
  # == Options
@@ -351,43 +471,51 @@ module AMQP
351
471
  # bindings. If the exchange has queue bindings the server does not
352
472
  # delete it but raises a channel exception instead (AMQP::Error).
353
473
  #
354
- def delete(opts = {})
355
- @mq.callback {
356
- @mq.send Protocol::Exchange::Delete.new({ :exchange => name,
357
- :nowait => true }.merge(opts))
358
- @mq.exchanges.delete name
359
- }
474
+ # @api public
475
+ def delete(opts = {}, &block)
476
+ @channel.once_open do
477
+ super(opts.fetch(:if_unused, false), opts.fetch(:nowait, false), &block)
478
+ end
479
+
480
+ # backwards compatibility
360
481
  nil
361
482
  end
362
483
 
363
-
484
+ # @return [Boolean] true if this exchange is durable
485
+ # @note Please make sure you read {Exchange Exchange class} documentation section on exchanges durability vs. messages
486
+ # persistence.
487
+ # @api public
364
488
  def durable?
365
489
  !!@opts[:durable]
366
490
  end # durable?
367
491
 
492
+ # @return [Boolean] true if this exchange is transient (non-durable)
493
+ # @note Please make sure you read {Exchange Exchange class} documentation section on exchanges durability vs. messages
494
+ # persistence.
495
+ # @api public
368
496
  def transient?
369
497
  !self.durable?
370
498
  end # transient?
499
+ alias temporary? transient?
371
500
 
501
+ # @return [Boolean] true if this exchange is automatically deleted when it is no longer used
502
+ # @api public
372
503
  def auto_deleted?
373
504
  !!@opts[:auto_delete]
374
505
  end # auto_deleted?
375
506
  alias auto_deletable? auto_deleted?
376
507
 
377
-
508
+ # Resets queue state. Useful for error handling.
509
+ # @api plugin
378
510
  def reset
379
- @deferred_status = nil
380
- initialize @mq, @type, @name, @opts
511
+ initialize(@channel, @type, @name, @opts)
381
512
  end
382
513
 
383
514
 
515
+ protected
384
516
 
385
- #
386
- # Implementation
387
- #
388
-
389
- def receive_response(response)
390
- self.callback && self.callback.call(self)
391
- end # receive_response
517
+ def self.add_default_options(type, name, opts, block)
518
+ { :exchange => name, :type => type, :nowait => block.nil? }.merge(opts)
519
+ end
392
520
  end # Exchange
393
521
  end # AMQP