amq-client 0.7.0.alpha34 → 0.7.0.alpha35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. data/.travis.yml +4 -0
  2. data/Gemfile +1 -1
  3. data/README.textile +1 -1
  4. data/bin/ci/before_build.sh +24 -0
  5. data/examples/eventmachine_adapter/extensions/rabbitmq/handling_confirm_select_ok.rb +2 -2
  6. data/examples/eventmachine_adapter/extensions/rabbitmq/publisher_confirmations_with_transient_messages.rb +1 -1
  7. data/examples/eventmachine_adapter/extensions/rabbitmq/publisher_confirmations_with_unroutable_message.rb +1 -1
  8. data/lib/amq/client.rb +29 -17
  9. data/lib/amq/client/adapter.rb +8 -504
  10. data/lib/amq/client/adapters/coolio.rb +4 -282
  11. data/lib/amq/client/adapters/event_machine.rb +4 -382
  12. data/lib/amq/client/async/adapter.rb +517 -0
  13. data/lib/amq/client/async/adapters/coolio.rb +291 -0
  14. data/lib/amq/client/async/adapters/event_machine.rb +392 -0
  15. data/lib/amq/client/async/adapters/eventmachine.rb +1 -0
  16. data/lib/amq/client/async/callbacks.rb +71 -0
  17. data/lib/amq/client/async/channel.rb +385 -0
  18. data/lib/amq/client/async/entity.rb +66 -0
  19. data/lib/amq/client/async/exchange.rb +157 -0
  20. data/lib/amq/client/async/extensions/rabbitmq/basic.rb +38 -0
  21. data/lib/amq/client/async/extensions/rabbitmq/confirm.rb +248 -0
  22. data/lib/amq/client/async/queue.rb +455 -0
  23. data/lib/amq/client/callbacks.rb +6 -65
  24. data/lib/amq/client/channel.rb +4 -376
  25. data/lib/amq/client/entity.rb +6 -57
  26. data/lib/amq/client/exchange.rb +4 -148
  27. data/lib/amq/client/extensions/rabbitmq/basic.rb +4 -28
  28. data/lib/amq/client/extensions/rabbitmq/confirm.rb +5 -240
  29. data/lib/amq/client/queue.rb +5 -450
  30. data/lib/amq/client/version.rb +1 -1
  31. data/spec/unit/client_spec.rb +10 -30
  32. metadata +16 -22
@@ -1,64 +1,13 @@
1
1
  # encoding: utf-8
2
2
 
3
- require "amq/client/callbacks"
4
- require "amq/client/openable"
3
+ require "amq/client/async/entity"
5
4
 
6
5
  module AMQ
7
6
  module Client
8
- module RegisterEntityMixin
9
- # @example Registering Channel implementation
10
- # Adapter.register_entity(:channel, Channel)
11
- # # ... so then I can do:
12
- # channel = client.channel(1)
13
- # # instead of:
14
- # channel = Channel.new(client, 1)
15
- def register_entity(name, klass)
16
- define_method(name) do |*args, &block|
17
- klass.new(self, *args, &block)
18
- end # define_method
19
- end # register_entity
20
- end # RegisterEntityMixin
21
-
22
- module ProtocolMethodHandlers
23
- def handle(klass, &block)
24
- AMQ::Client::HandlersRegistry.register(klass, &block)
25
- end
26
-
27
- def handlers
28
- AMQ::Client::HandlersRegistry.handlers
29
- end
30
- end # ProtocolMethodHandlers
31
-
32
-
33
- # AMQ entities, as implemented by AMQ::Client, have callbacks and can run them
34
- # when necessary.
35
- #
36
- # @note Exchanges and queues implementation is based on this class.
37
- #
38
- # @abstract
39
- module Entity
40
-
41
- #
42
- # Behaviors
43
- #
44
-
45
- include Openable
46
- include Callbacks
47
-
48
- #
49
- # API
50
- #
51
-
52
- # @return [Array<#call>]
53
- attr_reader :callbacks
54
-
55
-
56
- def initialize(connection)
57
- @connection = connection
58
- # Be careful with default values for #ruby hashes: h = Hash.new(Array.new); h[:key] ||= 1
59
- # won't assign anything to :key. MK.
60
- @callbacks = Hash.new
61
- end # initialize
62
- end # Entity
7
+ # backwards compatibility
8
+ # @private
9
+ RegisterEntityMixin = Async::RegisterEntityMixin
10
+ ProtocolMethodHandlers = Async::ProtocolMethodHandlers
11
+ Entity = Async::Entity
63
12
  end # Client
64
13
  end # AMQ
@@ -1,155 +1,11 @@
1
1
  # encoding: utf-8
2
2
 
3
- require "amq/client/entity"
4
- require "amq/client/server_named_entity"
3
+ require "amq/client/async/exchange"
5
4
 
6
5
  module AMQ
7
6
  module Client
8
- class Exchange
9
-
10
-
11
- include Entity
12
- include ServerNamedEntity
13
- extend ProtocolMethodHandlers
14
-
15
- TYPES = [:fanout, :direct, :topic, :headers].freeze
16
-
17
- class IncompatibleExchangeTypeError < StandardError
18
- def initialize(types, given)
19
- super("#{given.inspect} exchange type is unknown. Standard types are #{TYPES.inspect}, custom exchange types must begin with x-, for example: x-recent-history")
20
- end
21
- end
22
-
23
-
24
- #
25
- # API
26
- #
27
-
28
- # Channel this exchange belongs to.
29
- attr_reader :channel
30
-
31
- # Exchange name. May be server-generated or assigned directly.
32
- attr_reader :name
33
-
34
- # @return [Symbol] One of :direct, :fanout, :topic, :headers
35
- attr_reader :type
36
-
37
- def initialize(connection, channel, name, type = :fanout)
38
- if !(TYPES.include?(type.to_sym) || type.to_s =~ /^x-.+/i)
39
- raise IncompatibleExchangeTypeError.new(TYPES, type)
40
- end
41
-
42
- @connection = connection
43
- @channel = channel
44
- @name = name
45
- @type = type
46
-
47
- # register pre-declared exchanges
48
- if @name == AMQ::Protocol::EMPTY_STRING || @name =~ /^amq\.(fanout|topic)/
49
- @channel.register_exchange(self)
50
- end
51
-
52
- super(connection)
53
- end
54
-
55
-
56
- def fanout?
57
- @type == :fanout
58
- end
59
-
60
- def direct?
61
- @type == :direct
62
- end
63
-
64
- def topic?
65
- @type == :topic
66
- end
67
-
68
-
69
-
70
- def declare(passive = false, durable = false, auto_delete = false, nowait = false, arguments = nil, &block)
71
- @connection.send_frame(Protocol::Exchange::Declare.encode(@channel.id, @name, @type.to_s, passive, durable, auto_delete, false, nowait, arguments))
72
-
73
- unless nowait
74
- self.define_callback(:declare, &block)
75
- @channel.exchanges_awaiting_declare_ok.push(self)
76
- end
77
-
78
- self
79
- end
80
-
81
-
82
- def delete(if_unused = false, nowait = false, &block)
83
- @connection.send_frame(Protocol::Exchange::Delete.encode(@channel.id, @name, if_unused, nowait))
84
-
85
- unless nowait
86
- self.define_callback(:delete, &block)
87
-
88
- # TODO: delete itself from exchanges cache
89
- @channel.exchanges_awaiting_delete_ok.push(self)
90
- end
91
-
92
- self
93
- end # delete(if_unused = false, nowait = false)
94
-
95
-
96
- def publish(payload, routing_key = AMQ::Protocol::EMPTY_STRING, user_headers = {}, mandatory = false, immediate = false, frame_size = nil)
97
- headers = { :priority => 0, :delivery_mode => 2, :content_type => "application/octet-stream" }.merge(user_headers)
98
- @connection.send_frameset(Protocol::Basic::Publish.encode(@channel.id, payload, headers, @name, routing_key, mandatory, immediate, (frame_size || @connection.frame_max)))
99
-
100
- self
101
- end
102
-
103
-
104
- def on_return(&block)
105
- self.redefine_callback(:return, &block)
106
-
107
- self
108
- end # on_return(&block)
109
-
110
-
111
-
112
-
113
- def handle_declare_ok(method)
114
- @name = method.exchange if self.anonymous?
115
- @channel.register_exchange(self)
116
-
117
- self.exec_callback_once_yielding_self(:declare, method)
118
- end
119
-
120
- def handle_delete_ok(method)
121
- self.exec_callback_once(:delete, method)
122
- end # handle_delete_ok(method)
123
-
124
-
125
-
126
- self.handle(Protocol::Exchange::DeclareOk) do |connection, frame|
127
- method = frame.decode_payload
128
- channel = connection.channels[frame.channel]
129
- exchange = channel.exchanges_awaiting_declare_ok.shift
130
-
131
- exchange.handle_declare_ok(method)
132
- end # handle
133
-
134
-
135
- self.handle(Protocol::Exchange::DeleteOk) do |connection, frame|
136
- channel = connection.channels[frame.channel]
137
- exchange = channel.exchanges_awaiting_delete_ok.shift
138
- exchange.handle_delete_ok(frame.decode_payload)
139
- end # handle
140
-
141
-
142
- self.handle(Protocol::Basic::Return) do |connection, frame, content_frames|
143
- channel = connection.channels[frame.channel]
144
- method = frame.decode_payload
145
- exchange = channel.find_exchange(method.exchange)
146
-
147
- header = content_frames.shift
148
- body = content_frames.map { |frame| frame.payload }.join
149
-
150
- exchange.exec_callback(:return, method, header, body)
151
- end
152
-
153
- end # Exchange
7
+ # backwards compatibility
8
+ # @private
9
+ Exchange = Async::Exchange
154
10
  end # Client
155
11
  end # AMQ
@@ -1,36 +1,12 @@
1
1
  # encoding: utf-8
2
2
 
3
- require "amq/client/channel"
3
+ require "amq/client/async/extensions/rabbitmq/basic"
4
4
 
5
5
  # Basic.Nack
6
6
  module AMQ
7
7
  module Client
8
- module Extensions
9
- module RabbitMQ
10
- module Basic
11
- module ChannelMixin
12
-
13
- # Overrides {AMQ::Client::Channel#reject} behavior to use basic.nack.
14
- #
15
- # @api public
16
- # @see http://www.rabbitmq.com/amqp-0-9-1-quickref.html#basic.nack
17
- def reject(delivery_tag, requeue = true, multi = false)
18
- if multi
19
- @connection.send_frame(Protocol::Basic::Nack.encode(self.id, delivery_tag, multi, requeue))
20
- else
21
- super(delivery_tag, requeue)
22
- end
23
- end # reject
24
-
25
- end # ChannelMixin
26
- end # Basic
27
- end # RabbitMQ
28
- end # Extensions
29
-
30
- class Channel
31
- # use modules, the native Ruby way of extension of existing classes,
32
- # instead of reckless monkey-patching. MK.
33
- include Extensions::RabbitMQ::Basic::ChannelMixin
34
- end
8
+ # backwards compatibility
9
+ # @private
10
+ Extensions = Async::Extensions
35
11
  end # Client
36
12
  end # AMQ
@@ -1,246 +1,11 @@
1
1
  # encoding: utf-8
2
2
 
3
+ require "amq/client/async/extensions/rabbitmq/confirm"
4
+
3
5
  module AMQ
4
6
  module Client
5
- module Extensions
6
- module RabbitMQ
7
- # h2. Purpose
8
- # In case that the broker crashes, some messages can get lost.
9
- # Thanks to this extension, broker sends Basic.Ack when the message
10
- # is processed by the broker. In case of persistent messages, it must
11
- # be written to disk or ack'd on all the queues it was delivered to.
12
- # However it doesn't have to be necessarily 1:1, because the broker
13
- # can send Basic.Ack with multi flag to acknowledge multiple messages.
14
- #
15
- # So it provides clients a lightweight way of keeping track of which
16
- # messages have been processed by the broker and which would need
17
- # re-publishing in case of broker shutdown or network failure.
18
- #
19
- # Transactions are solving the same problem, but they are very slow:
20
- # confirmations are more than 100 times faster.
21
- #
22
- # h2. Workflow
23
- # * Client asks broker to confirm messages on given channel (Confirm.Select).
24
- # * Broker sends back Confirm.Select-Ok, unless we sent Confirm.Select with nowait=true.
25
- # * After each published message, the client receives Basic.Ack from the broker.
26
- # * If something bad happens inside the broker, it sends Basic.Nack.
27
- #
28
- # h2. Gotchas
29
- # Note that we don't keep track of messages awaiting confirmation.
30
- # It'd add a huge overhead and it's impossible to come up with one-suits-all solution.
31
- # If you want to create such module, you'll probably want to redefine Channel#after_publish,
32
- # so it will put messages into a queue and then handlers for Basic.Ack and Basic.Nack.
33
- # This is the reason why we pass every argument from Exchange#publish to Channel#after_publish.
34
- # You should not forget though, that both of these methods can have multi flag!
35
- #
36
- # Transactional channel cannot be put into confirm mode and a confirm
37
- # mode channel cannot be made transactional.
38
- #
39
- # If the connection between the publisher and broker drops with outstanding
40
- # confirms, it does not necessarily mean that the messages were lost, so
41
- # republishing may result in duplicate messages.
42
-
43
- # h2. Learn more
44
- # @see http://www.rabbitmq.com/blog/2011/02/10/introducing-publisher-confirms
45
- # @see http://www.rabbitmq.com/amqp-0-9-1-quickref.html#class.confirm
46
- # @see http://www.rabbitmq.com/amqp-0-9-1-reference.html#basic.ack
47
- module Confirm
48
- module ChannelMixin
49
-
50
- # Change publisher index. Publisher index is incremented
51
- # by 1 after each Basic.Publish starting at 1. This is done
52
- # on both client and server, hence this acknowledged messages
53
- # can be matched via its delivery-tag.
54
- #
55
- # @api private
56
- attr_writer :publisher_index
57
-
58
- # Publisher index is an index of the last message since
59
- # the confirmations were activated, started with 1. It's
60
- # incremented by 1 after each Basic.Publish starting at 1.
61
- # This is done on both client and server, hence this
62
- # acknowledged messages can be matched via its delivery-tag.
63
- #
64
- # @return [Integer] Current publisher index.
65
- # @api public
66
- def publisher_index
67
- @publisher_index ||= 1
68
- end
69
-
70
- # Resets publisher index to 0
71
- #
72
- # @api plugin
73
- def reset_publisher_index!
74
- @publisher_index = 0
75
- end
76
-
77
-
78
- # This method is executed after publishing of each message via {Exchage#publish}.
79
- # Currently it just increments publisher index by 1, so messages
80
- # can be actually matched.
81
- #
82
- # @api plugin
83
- def after_publish(*args)
84
- self.publisher_index += 1
85
- end
86
-
87
- # Turn on confirmations for this channel and, if given,
88
- # register callback for Confirm.Select-Ok.
89
- #
90
- # @raise [RuntimeError] Occurs when confirmations are already activated.
91
- # @raise [RuntimeError] Occurs when nowait is true and block is given.
92
- #
93
- # @param [Boolean] nowait Whether we expect Confirm.Select-Ok to be returned by the broker or not.
94
- # @yield [method] Callback which will be executed once we receive Confirm.Select-Ok.
95
- # @yieldparam [AMQ::Protocol::Confirm::SelectOk] method Protocol method class instance.
96
- #
97
- # @return [self] self.
98
- #
99
- # @see #confirm
100
- def confirm_select(nowait = false, &block)
101
- if nowait && block
102
- raise "You can't use Confirm.Select with nowait=true and a callback at the same time."
103
- end
104
-
105
- @uses_publisher_confirmations = true
106
- self.redefine_callback(:confirm_select, &block)
107
- @connection.send_frame(Protocol::Confirm::Select.encode(@id, nowait))
108
-
109
- self
110
- end
111
-
112
- # @return [Boolean]
113
- def uses_publisher_confirmations?
114
- @uses_publisher_confirmations
115
- end # uses_publisher_confirmations?
116
-
117
-
118
- # Turn on confirmations for this channel and, if given,
119
- # register callback for basic.ack from the broker.
120
- #
121
- # @raise [RuntimeError] Occurs when confirmations are already activated.
122
- # @raise [RuntimeError] Occurs when nowait is true and block is given.
123
- # @param [Boolean] nowait Whether we expect Confirm.Select-Ok to be returned by the broker or not.
124
- #
125
- # @yield [basick_ack] Callback which will be executed every time we receive Basic.Ack from the broker.
126
- # @yieldparam [AMQ::Protocol::Basic::Ack] basick_ack Protocol method class instance.
127
- #
128
- # @return [self] self.
129
- def on_ack(nowait = false, &block)
130
- self.use_publisher_confirmations! unless self.uses_publisher_confirmations?
131
-
132
- self.define_callback(:ack, &block) if block
133
-
134
- self
135
- end
136
-
137
-
138
- # Register error callback for Basic.Nack. It's called
139
- # when message(s) is rejected.
140
- #
141
- # @return [self] self
142
- def on_nack(&block)
143
- self.define_callback(:nack, &block) if block
144
-
145
- self
146
- end
147
-
148
-
149
-
150
-
151
- # Handler for Confirm.Select-Ok. By default, it just
152
- # executes hook specified via the #confirmations method
153
- # with a single argument, a protocol method class
154
- # instance (an instance of AMQ::Protocol::Confirm::SelectOk)
155
- # and then it deletes the callback, since Confirm.Select
156
- # is supposed to be sent just once.
157
- #
158
- # @api plugin
159
- def handle_select_ok(method)
160
- self.exec_callback_once(:confirm_select, method)
161
- end
162
-
163
- # Handler for Basic.Ack. By default, it just
164
- # executes hook specified via the #confirm method
165
- # with a single argument, a protocol method class
166
- # instance (an instance of AMQ::Protocol::Basic::Ack).
167
- #
168
- # @api plugin
169
- def handle_basic_ack(method)
170
- self.exec_callback(:ack, method)
171
- end
172
-
173
-
174
- # Handler for Basic.Nack. By default, it just
175
- # executes hook specified via the #confirm_failed method
176
- # with a single argument, a protocol method class
177
- # instance (an instance of AMQ::Protocol::Basic::Nack).
178
- #
179
- # @api plugin
180
- def handle_basic_nack(method)
181
- self.exec_callback(:nack, method)
182
- end
183
-
184
-
185
- def reset_state!
186
- super
187
-
188
- @uses_publisher_confirmations = false
189
- end
190
-
191
-
192
- def self.included(host)
193
- host.handle(Protocol::Confirm::SelectOk) do |connection, frame|
194
- method = frame.decode_payload
195
- channel = connection.channels[frame.channel]
196
- channel.handle_select_ok(method)
197
- end
198
-
199
- host.handle(Protocol::Basic::Ack) do |connection, frame|
200
- method = frame.decode_payload
201
- channel = connection.channels[frame.channel]
202
- channel.handle_basic_ack(method)
203
- end
204
-
205
- host.handle(Protocol::Basic::Nack) do |connection, frame|
206
- method = frame.decode_payload
207
- channel = connection.channels[frame.channel]
208
- channel.handle_basic_nack(method)
209
- end
210
- end # self.included(host)
211
- end # ChannelMixin
212
-
213
-
214
- module ExchangeMixin
215
- # Publish message and then run #after_publish on channel belonging
216
- # to the exchange. This is used for incrementing the publisher index.
217
- #
218
- # @api public
219
- # @see AMQ::Client::Exchange#publish
220
- # @see AMQ::Client::Extensions::RabbitMQ::Channel#publisher_index
221
- # @return [self] self
222
- def publish(*args)
223
- super(*args)
224
- @channel.after_publish(*args)
225
-
226
- self
227
- end # publish
228
- end # ExchangeMixin
229
- end # Confirm
230
- end # RabbitMQ
231
- end # Extensions
232
-
233
-
234
- class Channel
235
- # use modules, a native Ruby way of extension of existing classes,
236
- # instead of reckless monkey-patching. MK.
237
- include Extensions::RabbitMQ::Confirm::ChannelMixin
238
- end # Channel
239
-
240
- class Exchange
241
- # use modules, a native Ruby way of extension of existing classes,
242
- # instead of reckless monkey-patching. MK.
243
- include Extensions::RabbitMQ::Confirm::ExchangeMixin
244
- end # Exchange
7
+ # backwards compatibility
8
+ # @private
9
+ Extensions = Async::Extensions
245
10
  end # Client
246
11
  end # AMQ