rabbitmq-actors 2.0.0
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.
- checksums.yaml +7 -0
- data/.gitignore +101 -0
- data/.rspec +5 -0
- data/.travis.yml +12 -0
- data/Gemfile +4 -0
- data/README.md +602 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/rabbitmq/actors.rb +13 -0
- data/lib/rabbitmq/actors/base/agent.rb +108 -0
- data/lib/rabbitmq/actors/base/consumer.rb +105 -0
- data/lib/rabbitmq/actors/base/producer.rb +83 -0
- data/lib/rabbitmq/actors/patterns.rb +10 -0
- data/lib/rabbitmq/actors/patterns/headers/headers_consumer.rb +106 -0
- data/lib/rabbitmq/actors/patterns/headers/headers_producer.rb +64 -0
- data/lib/rabbitmq/actors/patterns/master_workers/master_producer.rb +61 -0
- data/lib/rabbitmq/actors/patterns/master_workers/worker.rb +63 -0
- data/lib/rabbitmq/actors/patterns/publish_subscribe/publisher.rb +72 -0
- data/lib/rabbitmq/actors/patterns/publish_subscribe/subscriber.rb +70 -0
- data/lib/rabbitmq/actors/patterns/routing/routing_consumer.rb +99 -0
- data/lib/rabbitmq/actors/patterns/routing/routing_producer.rb +75 -0
- data/lib/rabbitmq/actors/patterns/topics/topic_consumer.rb +105 -0
- data/lib/rabbitmq/actors/patterns/topics/topic_producer.rb +64 -0
- data/lib/rabbitmq/actors/testing.rb +8 -0
- data/lib/rabbitmq/actors/testing/rspec.rb +8 -0
- data/lib/rabbitmq/actors/testing/rspec/stub.rb +52 -0
- data/lib/rabbitmq/actors/version.rb +5 -0
- data/lib/rabbitmq/server.rb +18 -0
- data/rabbitmq-actors.gemspec +32 -0
- metadata +185 -0
@@ -0,0 +1,64 @@
|
|
1
|
+
require_relative '../../base/producer'
|
2
|
+
|
3
|
+
module RabbitMQ
|
4
|
+
module Actors
|
5
|
+
# A producer of messages routed to certain queues bound based on message headers matching.
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# RabbitMQ::Server.url = 'amqp://localhost'
|
9
|
+
#
|
10
|
+
# publisher = RabbitMQ::Actors::HeadersProducer.new(headers_name: 'reports', logger: Rails.logger)
|
11
|
+
# message = 'A report about USA economy'
|
12
|
+
# publisher.publish(message, message_id: '1234837633', headers: { 'type' => :economy, 'area' => 'USA'})
|
13
|
+
#
|
14
|
+
class HeadersProducer < Base::Producer
|
15
|
+
# @!attribute [r] headers_name
|
16
|
+
# @return [Bunny::Exchange] the headers exchange where to publish messages.
|
17
|
+
attr_reader :headers_name
|
18
|
+
|
19
|
+
# @param :headers_name [String] name of the headers exchange where to publish messages.
|
20
|
+
# @option opts [String] :reply_queue_name the name of the queue where a consumer should reply.
|
21
|
+
# @option opts [Logger] :logger the logger where to output info about this agent's activity.
|
22
|
+
def initialize(headers_name:, **opts)
|
23
|
+
super(opts.merge(headers_name: headers_name))
|
24
|
+
end
|
25
|
+
|
26
|
+
# Send a message to the RabbitMQ server.
|
27
|
+
# @param message [String] the message body to be sent.
|
28
|
+
# @param :message_id [String] user-defined id for replies to refer to this message using :correlation_id
|
29
|
+
# @param :headers [Hash] send the message only to queues bound to this exchange and matching any/all of these headers.
|
30
|
+
# @see Bunny::Exchange#publish for extra options:
|
31
|
+
# @option opts [Boolean] :persistent Should the message be persisted to disk?. Default true.
|
32
|
+
# @option opts [Boolean] :mandatory Should the message be returned if it cannot be routed to any queue?
|
33
|
+
# @option opts [Integer] :timestamp A timestamp associated with this message
|
34
|
+
# @option opts [Integer] :expiration Expiration time after which the message will be deleted
|
35
|
+
# @option opts [String] :type Message type, e.g. what type of event or command this message represents. Can be any string
|
36
|
+
# @option opts [String] :reply_to Queue name other apps should send the response to. Default to
|
37
|
+
# replay_queue_name if it was defined at creation time.
|
38
|
+
# @option opts [String] :content_type Message content type (e.g. application/json)
|
39
|
+
# @option opts [String] :content_encoding Message content encoding (e.g. gzip)
|
40
|
+
# @option opts [String] :correlation_id Message correlated to this one, e.g. what request this message is a reply for
|
41
|
+
# @option opts [Integer] :priority Message priority, 0 to 9. Not used by RabbitMQ, only applications
|
42
|
+
# @option opts [String] :user_id Optional user ID. Verified by RabbitMQ against the actual connection username
|
43
|
+
# @option opts [String] :app_id Optional application ID
|
44
|
+
def publish(message, message_id:, headers:, **opts)
|
45
|
+
super(message, opts.merge(message_id: message_id, headers: headers))
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
# Sets the exchange name to connect to.
|
51
|
+
# @see #initialize for the list of options that can be received.
|
52
|
+
def pre_initialize(**opts)
|
53
|
+
@headers_name = opts[:headers_name]
|
54
|
+
super
|
55
|
+
end
|
56
|
+
|
57
|
+
# The durable RabbitMQ headers exchange where to publish messages.
|
58
|
+
# @return [Bunny::Exchange]
|
59
|
+
def exchange
|
60
|
+
@exchange ||= channel.headers(headers_name, durable: true)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require_relative '../../base/producer'
|
2
|
+
|
3
|
+
module RabbitMQ
|
4
|
+
module Actors
|
5
|
+
|
6
|
+
# A producer of messages routed (via a default exchange) to a given queue.
|
7
|
+
# Used to distribute tasks among several worker processes listening a shared queue.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# RabbitMQ::Server.url = 'amqp://localhost'
|
11
|
+
#
|
12
|
+
# master = RabbitMQ::Actors::MasterProducer.new(
|
13
|
+
# queue_name: 'purchases',
|
14
|
+
# auto_delete: false,
|
15
|
+
# reply_queue_name: 'confirmations',
|
16
|
+
# logger: Rails.logger)
|
17
|
+
#
|
18
|
+
# message = { stock: 'Apple', number: 1000 }.to_json
|
19
|
+
# master.publish(message, message_id: '1234837325', content_type: "application/json")
|
20
|
+
#
|
21
|
+
class MasterProducer < Base::Producer
|
22
|
+
# @param :queue_name [String] name of the durable queue where to publish messages.
|
23
|
+
# @option opts [Boolean] :auto_delete (true) if the queue will be deleted when
|
24
|
+
# there are no more consumers subscribed to it.
|
25
|
+
# @option opts [String] :reply_queue_name the name of the queue where a consumer should reply.
|
26
|
+
# @option opts [Logger] :logger the logger where to output info about this agent's activity.
|
27
|
+
def initialize(queue_name:, **opts)
|
28
|
+
super(opts.merge(queue_name: queue_name, exclusive: false))
|
29
|
+
end
|
30
|
+
|
31
|
+
# Send a message to the RabbitMQ server.
|
32
|
+
# @param message [String] the message body to be sent.
|
33
|
+
# @param :message_id [String] user-defined id for replies to refer to this message using :correlation_id
|
34
|
+
# @see Bunny::Exchange#publish for extra options:
|
35
|
+
# @option opts [Boolean] :persistent Should the message be persisted to disk?. Default true.
|
36
|
+
# @option opts [Boolean] :mandatory Should the message be returned if it cannot be routed to any queue?
|
37
|
+
# @option opts [Integer] :timestamp A timestamp associated with this message
|
38
|
+
# @option opts [Integer] :expiration Expiration time after which the message will be deleted
|
39
|
+
# @option opts [String] :type Message type, e.g. what type of event or command this message represents. Can be any string
|
40
|
+
# @option opts [String] :reply_to Queue name other apps should send the response to. Default to
|
41
|
+
# replay_queue_name if it was defined at creation time.
|
42
|
+
# @option opts [String] :content_type Message content type (e.g. application/json)
|
43
|
+
# @option opts [String] :content_encoding Message content encoding (e.g. gzip)
|
44
|
+
# @option opts [String] :correlation_id Message correlated to this one, e.g. what request this message is a reply for
|
45
|
+
# @option opts [Integer] :priority Message priority, 0 to 9. Not used by RabbitMQ, only applications
|
46
|
+
# @option opts [String] :user_id Optional user ID. Verified by RabbitMQ against the actual connection username
|
47
|
+
# @option opts [String] :app_id Optional application ID
|
48
|
+
def publish(message, message_id:, **opts)
|
49
|
+
super(message, opts.merge(message_id: message_id, routing_key: queue.name))
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
# The default RabbitMQ exchange where to publish messages
|
55
|
+
# @return [Bunny::Exchange]
|
56
|
+
def exchange
|
57
|
+
@exchange ||= channel.default_exchange
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require_relative '../../base/consumer'
|
2
|
+
|
3
|
+
module RabbitMQ
|
4
|
+
module Actors
|
5
|
+
# A consumer of messages from RabbitMQ based on queue name.
|
6
|
+
# @abstract Subclass and override #perform to define your customized worker class.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# class MyListener < RabbitMQ::Actors::Worker
|
10
|
+
# class_attribute :queue_name, instance_writer: false
|
11
|
+
#
|
12
|
+
# def initialize
|
13
|
+
# super(queue_name: queue_name,
|
14
|
+
# manual_ack: true
|
15
|
+
# logger: Rails.logger,
|
16
|
+
# on_cancellation: ->{ ActiveRecord::Base.connection.close }
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# private
|
20
|
+
#
|
21
|
+
# def perform(**task)
|
22
|
+
# answer, transaction_guid = JSON.parse(task[:body]), task[:properties][:correlation_id]
|
23
|
+
# transaction = referred_transaction(transaction_guid: transaction_guid, tid: answer['tid'])
|
24
|
+
# return _no_transaction!(message_id: transaction_guid, transaction: transaction) if transaction.errors.present?
|
25
|
+
# update_transaction(transaction, answer.symbolize_keys)
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# def referred_transaction(transaction_guid:, tid:)
|
29
|
+
# ...
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# def update_transaction(purchase, **attrs)
|
33
|
+
# ...
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# def _no_transaction!(message_id:, transaction:)
|
37
|
+
# log_event(type: 'Transaction',
|
38
|
+
# message_id: message_id,
|
39
|
+
# description: 'ERROR: answer does not identify any transaction',
|
40
|
+
# payload: { errors: transaction.errors.full_messages },
|
41
|
+
# severity: :high)
|
42
|
+
# transaction
|
43
|
+
# end
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# RabbitMQ::Server.url = 'amqp://localhost'
|
47
|
+
#
|
48
|
+
# MyListener.queue_name = "transactions"
|
49
|
+
# MyListener.new.start!
|
50
|
+
#
|
51
|
+
class Worker < Base::Consumer
|
52
|
+
# @param :queue_name [String] name of the durable queue where to receive messages from.
|
53
|
+
# @option opts [Boolean] :manual_ack to acknowledge messages to the RabbitMQ server
|
54
|
+
# once executed.
|
55
|
+
# @option opts [Proc] :on_cancellation to be executed before the worker is terminated
|
56
|
+
# @option opts [Logger] :logger the logger where to output info about this agent's activity.
|
57
|
+
# Rest of options required by your subclass.
|
58
|
+
def initialize(queue_name:, **opts)
|
59
|
+
super(opts.merge(queue_name: queue_name, exclusive: false))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require_relative '../../base/producer'
|
2
|
+
|
3
|
+
module RabbitMQ
|
4
|
+
module Actors
|
5
|
+
# A producer of messages routed to all the consumers bound to the exchange.
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# RabbitMQ::Server.url = 'amqp://localhost'
|
9
|
+
#
|
10
|
+
# publisher = RabbitMQ::Actors::Publisher.new(exchange_name: 'sports', logger: Rails.logger)
|
11
|
+
#
|
12
|
+
# message = {
|
13
|
+
# championship: 'Premier League',
|
14
|
+
# match: {
|
15
|
+
# team_1: 'Chelsea',
|
16
|
+
# team_2: 'Manchester City',
|
17
|
+
# date: '03-Sep-2016',
|
18
|
+
# score: '2-2'
|
19
|
+
# } }.to_json
|
20
|
+
#
|
21
|
+
# publisher.publish(message, message_id: '1234837633', content_type: "application/json")
|
22
|
+
#
|
23
|
+
class Publisher < Base::Producer
|
24
|
+
# @!attribute [r] exchange_name
|
25
|
+
# @return [Bunny::Exchange] the fanout exchange where to publish messages.
|
26
|
+
attr_reader :exchange_name
|
27
|
+
|
28
|
+
# @param :exchange_name [String] name of the exchange where to publish messages.
|
29
|
+
# @option opts [String] :reply_queue_name the name of the queue where a consumer should reply.
|
30
|
+
# @option opts [Logger] :logger the logger where to output info about this agent's activity.
|
31
|
+
def initialize(exchange_name:, **opts)
|
32
|
+
super(opts.merge(exchange_name: exchange_name))
|
33
|
+
end
|
34
|
+
|
35
|
+
# Send a message to the RabbitMQ server.
|
36
|
+
# @param message [String] the message body to be sent.
|
37
|
+
# @param :message_id [String] user-defined id for replies to refer to this message using :correlation_id
|
38
|
+
# @see Bunny::Exchange#publish for extra options:
|
39
|
+
# @option opts [Boolean] :persistent Should the message be persisted to disk?. Default true.
|
40
|
+
# @option opts [Boolean] :mandatory Should the message be returned if it cannot be routed to any queue?
|
41
|
+
# @option opts [Integer] :timestamp A timestamp associated with this message
|
42
|
+
# @option opts [Integer] :expiration Expiration time after which the message will be deleted
|
43
|
+
# @option opts [String] :type Message type, e.g. what type of event or command this message represents. Can be any string
|
44
|
+
# @option opts [String] :reply_to Queue name other apps should send the response to. Default to
|
45
|
+
# replay_queue_name if it was defined at creation time.
|
46
|
+
# @option opts [String] :content_type Message content type (e.g. application/json)
|
47
|
+
# @option opts [String] :content_encoding Message content encoding (e.g. gzip)
|
48
|
+
# @option opts [String] :correlation_id Message correlated to this one, e.g. what request this message is a reply for
|
49
|
+
# @option opts [Integer] :priority Message priority, 0 to 9. Not used by RabbitMQ, only applications
|
50
|
+
# @option opts [String] :user_id Optional user ID. Verified by RabbitMQ against the actual connection username
|
51
|
+
# @option opts [String] :app_id Optional application ID
|
52
|
+
def publish(message, message_id:, **opts)
|
53
|
+
super(message, opts.merge(message_id: message_id))
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
# Sets the exchange name to connect to.
|
59
|
+
# @see #initialize for the list of options that can be received.
|
60
|
+
def pre_initialize(**opts)
|
61
|
+
@exchange_name = opts[:exchange_name]
|
62
|
+
super
|
63
|
+
end
|
64
|
+
|
65
|
+
# The durable RabbitMQ fanout exchange where to publish messages.
|
66
|
+
# @return [Bunny::Exchange]
|
67
|
+
def exchange
|
68
|
+
@exchange ||= channel.fanout(exchange_name, durable: true)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require_relative '../../base/consumer'
|
2
|
+
|
3
|
+
module RabbitMQ
|
4
|
+
module Actors
|
5
|
+
# A consumer of all messages produced by a fanout RabbitMQ exchange.
|
6
|
+
# @abstract Subclass and override #perform to define your customized subscriber class.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# class ScoresListener < RabbitMQ::Actors::Subscriber
|
10
|
+
# def initialize
|
11
|
+
# super(exchange_name: 'scores',
|
12
|
+
# logger: Rails.logger,
|
13
|
+
# on_cancellation: ->{ ActiveRecord::Base.connection.close })
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# private
|
17
|
+
#
|
18
|
+
# def perform(**task)
|
19
|
+
# match_data = JSON.parse(task[:body])
|
20
|
+
# process_match(match_data)
|
21
|
+
# end
|
22
|
+
# ...
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# RabbitMQ::Server.url = 'amqp://localhost'
|
26
|
+
#
|
27
|
+
# ScoresListener.new.start!
|
28
|
+
#
|
29
|
+
class Subscriber < Base::Consumer
|
30
|
+
# @!attribute [r] exchange_name
|
31
|
+
# @return [Bunny::Exchange] the exchange where to get messages from.
|
32
|
+
attr_reader :exchange_name
|
33
|
+
|
34
|
+
# @param :exchange_name [String] name of the exchange where to consume messages from.
|
35
|
+
# @option opts [Proc] :on_cancellation to be executed before the worker is terminated
|
36
|
+
# @option opts [Logger] :logger the logger where to output info about this agent's activity.
|
37
|
+
# Rest of options required by your subclass.
|
38
|
+
def initialize(exchange_name:, **opts)
|
39
|
+
super(opts.merge(exchange_name: exchange_name))
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
# Set exchange_name this worker is bound to.
|
45
|
+
# @see #initialize for the list of options that can be received.
|
46
|
+
def pre_initialize(**opts)
|
47
|
+
@exchange_name = opts[:exchange_name]
|
48
|
+
super
|
49
|
+
end
|
50
|
+
|
51
|
+
# Bind this worker's queue to the exchange
|
52
|
+
# @see #initialize for the list of options that can be received.
|
53
|
+
def post_initialize(**opts)
|
54
|
+
bind_queue_to_exchange
|
55
|
+
super
|
56
|
+
end
|
57
|
+
|
58
|
+
# The durable fanout RabbitMQ exchange from where messages are received
|
59
|
+
# @return [Bunny::Exchange]
|
60
|
+
def exchange
|
61
|
+
@exchange ||= channel.fanout(exchange_name, durable: true)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Bind this worker's listening queue to the exchange to receive all messages produced.
|
65
|
+
def bind_queue_to_exchange
|
66
|
+
queue.bind(exchange)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require_relative '../../base/consumer'
|
2
|
+
|
3
|
+
module RabbitMQ
|
4
|
+
module Actors
|
5
|
+
# A consumer of messages from RabbitMQ based on routing keys.
|
6
|
+
# @abstract Subclass and override #perform to define your customized routing worker class.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# class TennisListener < RabbitMQ::Actors::RoutingConsumer
|
10
|
+
# def initialize
|
11
|
+
# super(exchange_name: 'sports',
|
12
|
+
# binding_keys: ['tennis'],
|
13
|
+
# logger: Rails.logger,
|
14
|
+
# on_cancellation: ->{ ActiveRecord::Base.connection.close })
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# private
|
18
|
+
#
|
19
|
+
# def perform(**task)
|
20
|
+
# match_data = JSON.parse(task[:body])
|
21
|
+
# process_tennis_match(match_data)
|
22
|
+
# end
|
23
|
+
# ...
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# class FootballListener < RabbitMQ::Actors::RoutingConsumer
|
27
|
+
# def initialize
|
28
|
+
# super(exchange_name: 'sports',
|
29
|
+
# binding_keys: ['football', 'soccer'],
|
30
|
+
# logger: Rails.logger,
|
31
|
+
# on_cancellation: ->{ ActiveRecord::Base.connection.close })
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# private
|
35
|
+
#
|
36
|
+
# def perform(**task)
|
37
|
+
# match_data = JSON.parse(task[:body])
|
38
|
+
# process_footbal_match(match_data)
|
39
|
+
# end
|
40
|
+
# ...
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# RabbitMQ::Server.url = 'amqp://localhost'
|
44
|
+
#
|
45
|
+
# TennisListener.new.start!
|
46
|
+
# FootballListener.new.start!
|
47
|
+
#
|
48
|
+
class RoutingConsumer < Base::Consumer
|
49
|
+
# @!attribute [r] exchange_name
|
50
|
+
# @return [Bunny::Exchange] the exchange where to get messages from.
|
51
|
+
attr_reader :exchange_name
|
52
|
+
|
53
|
+
# @!attribute [r] binding_keys
|
54
|
+
# @return [String, Array] the routing keys this worker is interested in.
|
55
|
+
attr_reader :binding_keys
|
56
|
+
|
57
|
+
# @param :exchange_name [String] name of the exchange where to consume messages from.
|
58
|
+
# @param :binding_keys [String, Array] list of routing keys this worker is interested in.
|
59
|
+
# Default to all: '#'
|
60
|
+
# @option opts [Proc] :on_cancellation to be executed before the worker is terminated
|
61
|
+
# @option opts [Logger] :logger the logger where to output info about this agent's activity.
|
62
|
+
# Rest of options required by your subclass.
|
63
|
+
def initialize(exchange_name:, binding_keys: '#', **opts)
|
64
|
+
super(opts.merge(exchange_name: exchange_name, binding_keys: binding_keys))
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
# Set exchange_name and binding_keys this worker is bound to.
|
70
|
+
# @see #initialize for the list of options that can be received.
|
71
|
+
def pre_initialize(**opts)
|
72
|
+
@exchange_name = opts[:exchange_name]
|
73
|
+
@binding_keys = Array(opts[:binding_keys])
|
74
|
+
super
|
75
|
+
end
|
76
|
+
|
77
|
+
# Bind this worker's queue to the exchange and to the given binding_keys
|
78
|
+
# @see #initialize for the list of options that can be received.
|
79
|
+
def post_initialize(**opts)
|
80
|
+
bind_queue_to_exchange_routing_keys
|
81
|
+
super
|
82
|
+
end
|
83
|
+
|
84
|
+
# The durable direct RabbitMQ exchange from where messages are received
|
85
|
+
# @return [Bunny::Exchange]
|
86
|
+
def exchange
|
87
|
+
@exchange ||= channel.direct(exchange_name, durable: true)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Bind this worker's listening queue to the exchange and receive only messages with routing key
|
91
|
+
# one of the given binding_keys.
|
92
|
+
def bind_queue_to_exchange_routing_keys
|
93
|
+
binding_keys.each do |key|
|
94
|
+
queue.bind(exchange, routing_key: key)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require_relative '../../base/producer'
|
2
|
+
|
3
|
+
module RabbitMQ
|
4
|
+
module Actors
|
5
|
+
# A producer of messages routed to all the queues bound to the message's routing_key
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# RabbitMQ::Server.url = 'amqp://localhost'
|
9
|
+
#
|
10
|
+
# publisher = RabbitMQ::Actors::RoutingProducer.new(
|
11
|
+
# exchange_name: 'sports',
|
12
|
+
# replay_queue_name: 'scores',
|
13
|
+
# logger: Rails.logger)
|
14
|
+
#
|
15
|
+
# message = {
|
16
|
+
# championship: 'Wimbledon',
|
17
|
+
# match: {
|
18
|
+
# player_1: 'Rafa Nadal',
|
19
|
+
# player_2: 'Roger Federed',
|
20
|
+
# date: '01-Jul-2016'
|
21
|
+
# } }.to_json
|
22
|
+
#
|
23
|
+
# publisher.publish(message, message_id: '1234837633', content_type: "application/json", routing_key: 'tennis')
|
24
|
+
#
|
25
|
+
class RoutingProducer < Base::Producer
|
26
|
+
# @!attribute [r] exchange_name
|
27
|
+
# @return [Bunny::Exchange] the routing exchange where to publish messages.
|
28
|
+
attr_reader :exchange_name
|
29
|
+
|
30
|
+
# @param :exchange_name [String] name of the exchange where to publish messages.
|
31
|
+
# @option opts [String] :reply_queue_name the name of the queue where a consumer should reply.
|
32
|
+
# @option opts [Logger] :logger the logger where to output info about this agent's activity.
|
33
|
+
def initialize(exchange_name:, **opts)
|
34
|
+
super(opts.merge(exchange_name: exchange_name))
|
35
|
+
end
|
36
|
+
|
37
|
+
# Send a message to the RabbitMQ server.
|
38
|
+
# @param message [String] the message body to be sent.
|
39
|
+
# @param :message_id [String] user-defined id for replies to refer to this message using :correlation_id
|
40
|
+
# @param :routing_key [String] send the message only to queues bound to this exchange and this routing_key
|
41
|
+
# @see Bunny::Exchange#publish for extra options:
|
42
|
+
# @option opts [Boolean] :persistent Should the message be persisted to disk?. Default true.
|
43
|
+
# @option opts [Boolean] :mandatory Should the message be returned if it cannot be routed to any queue?
|
44
|
+
# @option opts [Integer] :timestamp A timestamp associated with this message
|
45
|
+
# @option opts [Integer] :expiration Expiration time after which the message will be deleted
|
46
|
+
# @option opts [String] :type Message type, e.g. what type of event or command this message represents. Can be any string
|
47
|
+
# @option opts [String] :reply_to Queue name other apps should send the response to. Default to
|
48
|
+
# replay_queue_name if it was defined at creation time.
|
49
|
+
# @option opts [String] :content_type Message content type (e.g. application/json)
|
50
|
+
# @option opts [String] :content_encoding Message content encoding (e.g. gzip)
|
51
|
+
# @option opts [String] :correlation_id Message correlated to this one, e.g. what request this message is a reply for
|
52
|
+
# @option opts [Integer] :priority Message priority, 0 to 9. Not used by RabbitMQ, only applications
|
53
|
+
# @option opts [String] :user_id Optional user ID. Verified by RabbitMQ against the actual connection username
|
54
|
+
# @option opts [String] :app_id Optional application ID
|
55
|
+
def publish(message, message_id:, routing_key:, **opts)
|
56
|
+
super(message, opts.merge(message_id: message_id, routing_key: routing_key))
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
# Sets the exchange name to connect to.
|
62
|
+
# @see #initialize for the list of options that can be received.
|
63
|
+
def pre_initialize(**opts)
|
64
|
+
@exchange_name = opts[:exchange_name]
|
65
|
+
super
|
66
|
+
end
|
67
|
+
|
68
|
+
# The durable RabbitMQ direct exchange where to publish messages.
|
69
|
+
# @return [Bunny::Exchange]
|
70
|
+
def exchange
|
71
|
+
@exchange ||= channel.direct(exchange_name, durable: true)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|