rabbitmq-actors 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|