Skip to content

Commit 712be82

Browse files
authored
fix: add custom RMQ option (#15)
1 parent e24518b commit 712be82

File tree

5 files changed

+109
-51
lines changed

5 files changed

+109
-51
lines changed

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -92,19 +92,19 @@ func main() {
9292
defer consumerChannel.Close()
9393
rmqConsumer := consumer.NewConsumer(
9494
consumerOpts.ConsumerPlatformRabbitMQ,
95-
consumerOpts.WithRabbitMQConsumerConfig(&consumerOpts.RabbitMQConsumerConfig{
96-
ConsumerChannel: consumerChannel,
97-
ReQueueChannel: publisherChannel,
98-
}),
95+
consumerOpts.WithRabbitMQConsumerConfig(consumerOpts.RabbitMQConfigWithDefaultTopicFanOutPattern(
96+
consumerChannel,
97+
publisherChannel,
98+
"goqueue", // exchange name
99+
[]string{"goqueue.payments.#"}, // routing keys pattern
100+
)),
99101
consumerOpts.WithConsumerID("consumer_id"),
100102
consumerOpts.WithMiddlewares(
101103
middleware.HelloWorldMiddlewareExecuteAfterInboundMessageHandler(),
102104
middleware.HelloWorldMiddlewareExecuteBeforeInboundMessageHandler(),
103105
),
104106
consumerOpts.WithMaxRetryFailedMessage(3),
105107
consumerOpts.WithBatchMessageSize(1),
106-
consumerOpts.WithActionsPatternSubscribed("goqueue.payments.#", "goqueue.users.#"),
107-
consumerOpts.WithTopicName("goqueue"),
108108
consumerOpts.WithQueueName("consumer_queue"),
109109
)
110110

examples/rabbitmq/main.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,19 +65,19 @@ func main() {
6565
defer consumerChannel.Close()
6666
rmqConsumer := consumer.NewConsumer(
6767
consumerOpts.ConsumerPlatformRabbitMQ,
68-
consumerOpts.WithRabbitMQConsumerConfig(&consumerOpts.RabbitMQConsumerConfig{
69-
ConsumerChannel: consumerChannel,
70-
ReQueueChannel: publisherChannel,
71-
}),
68+
consumerOpts.WithRabbitMQConsumerConfig(consumerOpts.RabbitMQConfigWithDefaultTopicFanOutPattern(
69+
consumerChannel,
70+
publisherChannel,
71+
"goqueue", // exchange name
72+
[]string{"goqueue.payments.#"}, // routing keys pattern
73+
)),
7274
consumerOpts.WithConsumerID("consumer_id"),
7375
consumerOpts.WithMiddlewares(
7476
middleware.HelloWorldMiddlewareExecuteAfterInboundMessageHandler(),
7577
middleware.HelloWorldMiddlewareExecuteBeforeInboundMessageHandler(),
7678
),
7779
consumerOpts.WithMaxRetryFailedMessage(3),
7880
consumerOpts.WithBatchMessageSize(1),
79-
consumerOpts.WithActionsPatternSubscribed("goqueue.payments.#", "goqueue.users.#"),
80-
consumerOpts.WithTopicName("goqueue"),
8181
consumerOpts.WithQueueName("consumer_queue"),
8282
)
8383

internal/consumer/rabbitmq/blackbox_consumer_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -192,15 +192,15 @@ func (s *rabbitMQTestSuite) TestConsumerWithoutExchangePatternProvided() {
192192
func (s *rabbitMQTestSuite) TestConsumerWithExchangePatternProvided() {
193193
s.seedPublish(string(headerVal.ContentTypeJSON), testAction)
194194
rmqSubs := rmq.NewConsumer(
195-
consumerOpts.WithRabbitMQConsumerConfig(&consumerOpts.RabbitMQConsumerConfig{
196-
ConsumerChannel: s.consumerChannel,
197-
ReQueueChannel: s.publishChannel,
198-
}),
195+
consumerOpts.WithRabbitMQConsumerConfig(consumerOpts.RabbitMQConfigWithDefaultTopicFanOutPattern(
196+
s.consumerChannel,
197+
s.publishChannel,
198+
testExchange,
199+
[]string{"goqueue.action.#"},
200+
)),
199201
consumerOpts.WithBatchMessageSize(1),
200202
consumerOpts.WithMiddlewares(middleware.HelloWorldMiddlewareExecuteAfterInboundMessageHandler()),
201203
consumerOpts.WithQueueName(rabbitMQTestQueueName),
202-
consumerOpts.WithActionsPatternSubscribed("goqueue.action.#"), //exchange pattern provided in constructor
203-
consumerOpts.WithTopicName(testExchange), //exchange name provided in constructor
204204
)
205205

206206
msgHandler := handler(s.T(), s.getMockData(testAction))

internal/consumer/rabbitmq/consumer.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,11 @@ func NewConsumer(
4141
requeueChannel: opt.RabbitMQConsumerConfig.ReQueueChannel,
4242
option: opt,
4343
}
44-
if len(opt.ActionsPatternSubscribed) > 0 && opt.TopicName != "" {
44+
if opt.RabbitMQConsumerConfig.QueueDeclareConfig != nil &&
45+
opt.RabbitMQConsumerConfig.QueueBindConfig != nil {
4546
rmqHandler.initQueue()
4647
}
48+
4749
rmqHandler.initConsumer()
4850
return rmqHandler
4951
}
@@ -54,26 +56,25 @@ func (r *rabbitMQ) initQueue() {
5456
// Returns an instance of amqp.Queue and any error encountered.
5557
// Please refer to the RabbitMQ documentation for more information on the parameters.
5658
// https://www.rabbitmq.com/amqp-0-9-1-reference.html#queue.declare
57-
// (from bxcodec: please raise a PR if you need a custom queue argument)
5859
_, err := r.consumerChannel.QueueDeclare(
5960
r.option.QueueName,
60-
true,
61-
false,
62-
false,
63-
false,
64-
nil,
61+
r.option.RabbitMQConsumerConfig.QueueDeclareConfig.Durable,
62+
r.option.RabbitMQConsumerConfig.QueueDeclareConfig.AutoDelete,
63+
r.option.RabbitMQConsumerConfig.QueueDeclareConfig.Exclusive,
64+
r.option.RabbitMQConsumerConfig.QueueDeclareConfig.NoWait,
65+
r.option.RabbitMQConsumerConfig.QueueDeclareConfig.Args,
6566
)
6667
if err != nil {
6768
logrus.Fatal("error declaring the queue, ", err)
6869
}
6970

70-
for _, eventType := range r.option.ActionsPatternSubscribed {
71+
for _, eventType := range r.option.RabbitMQConsumerConfig.QueueBindConfig.RoutingKeys {
7172
err = r.consumerChannel.QueueBind(
7273
r.option.QueueName,
7374
eventType,
74-
r.option.TopicName,
75-
false,
76-
nil,
75+
r.option.RabbitMQConsumerConfig.QueueBindConfig.ExchangeName,
76+
r.option.RabbitMQConsumerConfig.QueueBindConfig.NoWait,
77+
r.option.RabbitMQConsumerConfig.QueueBindConfig.Args,
7778
)
7879
if err != nil {
7980
logrus.Fatal("error binding the queue, ", err)

options/consumer/consumer.go

Lines changed: 79 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,6 @@ type ConsumerOption struct {
2323
// Middlewares is a list of middleware functions to be applied to the inbound message handler.
2424
Middlewares []interfaces.InboundMessageHandlerMiddlewareFunc
2525

26-
// ActionsPatternSubscribed specifies the list of action patterns that the consumer is subscribed to.
27-
ActionsPatternSubscribed []string
28-
29-
// TopicName specifies the name of the topic to consume messages from.
30-
TopicName string
31-
3226
// MaxRetryFailedMessage specifies the maximum number of times a failed message should be retried.
3327
MaxRetryFailedMessage int64
3428

@@ -68,22 +62,6 @@ func WithMiddlewares(middlewares ...interfaces.InboundMessageHandlerMiddlewareFu
6862
}
6963
}
7064

71-
// WithActionsPatternSubscribed sets the actions that the consumer will subscribe to.
72-
// It takes a variadic parameter `actions` which represents the actions to be subscribed.
73-
// The actions are stored in the `ActionsPatternSubscribed` field of the `ConsumerOption` struct.
74-
func WithActionsPatternSubscribed(actions ...string) ConsumerOptionFunc {
75-
return func(opt *ConsumerOption) {
76-
opt.ActionsPatternSubscribed = actions
77-
}
78-
}
79-
80-
// WithTopicName sets the topic name for the consumer option.
81-
func WithTopicName(name string) ConsumerOptionFunc {
82-
return func(opt *ConsumerOption) {
83-
opt.TopicName = name
84-
}
85-
}
86-
8765
// WithMaxRetryFailedMessage sets the maximum number of retries for failed messages.
8866
// It takes an integer parameter 'n' and returns an ConsumerOptionFunc.
8967
// The ConsumerOptionFunc updates the 'MaxRetryFailedMessage' field of the ConsumerOption struct.
@@ -122,10 +100,89 @@ type RabbitMQConsumerConfig struct {
122100
ConsumerChannel *amqp.Channel
123101
// ReQueueChannel is the channel used for re-queuing messages in RabbitMQ.
124102
ReQueueChannel *amqp.Channel
103+
104+
// QueueDeclareConfig specifies the configuration for declaring a RabbitMQ queue.
105+
QueueDeclareConfig *RabbitMQQueueDeclareConfig
106+
107+
// QueueBindConfig specifies the configuration for binding a queue to an exchange in RabbitMQ.
108+
QueueBindConfig *RabbitMQQueueBindConfig
109+
}
110+
111+
// RabbitMQQueueDeclareConfig represents the configuration options for declaring a RabbitMQ queue.
112+
// * Durable and Non-Auto-Deleted queues will survive server restarts and remain
113+
// when there are no remaining consumers or bindings. Persistent publishings will
114+
// be restored in this queue on server restart. These queues are only able to be
115+
// bound to durable exchanges.
116+
// * Non-Durable and Auto-Deleted queues will not be redeclared on server restart
117+
// and will be deleted by the server after a short time when the last consumer is
118+
// canceled or the last consumer's channel is closed. Queues with this lifetime
119+
// can also be deleted normally with QueueDelete. These durable queues can only
120+
// be bound to non-durable exchanges.
121+
// * Non-Durable and Non-Auto-Deleted queues will remain declared as long as the
122+
// server is running regardless of how many consumers. This lifetime is useful
123+
// for temporary topologies that may have long delays between consumer activity.
124+
// These queues can only be bound to non-durable exchanges.
125+
// * Durable and Auto-Deleted queues will be restored on server restart, but without
126+
// active consumers will not survive and be removed. This Lifetime is unlikely
127+
// to be useful.
128+
// * Exclusive queues are only accessible by the connection that declares them and
129+
// will be deleted when the connection closes. Channels on other connections
130+
// will receive an error when attempting to declare, bind, consume, purge or
131+
// delete a queue with the same name.
132+
// * When noWait is true, the queue will assume to be declared on the server. A
133+
// channel exception will arrive if the conditions are met for existing queues
134+
// or attempting to modify an existing queue from a different connection.
135+
// When the error return value is not nil, you can assume the queue could not be
136+
// declared with these parameters, and the channel will be closed.
137+
type RabbitMQQueueDeclareConfig struct {
138+
Durable bool // Whether the queue should survive a broker restart.
139+
AutoDelete bool // Whether the queue should be deleted when there are no more consumers.
140+
Exclusive bool // Whether the queue should be exclusive to the connection that declares it.
141+
NoWait bool // Whether to wait for a response from the server after declaring the queue.
142+
Args amqp.Table // Additional arguments to be passed when declaring the queue.
143+
}
144+
145+
// RabbitMQQueueBindConfig represents the configuration options for binding a queue to an exchange in RabbitMQ.
146+
type RabbitMQQueueBindConfig struct {
147+
RoutingKeys []string // The routing key to use for the binding.
148+
ExchangeName string // The name of the exchange to bind to.
149+
NoWait bool // Whether to wait for a response from the server.
150+
Args amqp.Table // Additional arguments for the binding.
125151
}
126152

127153
const (
128154
ConsumerPlatformRabbitMQ = options.PlatformRabbitMQ
129155
ConsumerPlatformGooglePubSub = options.PlatformGooglePubSub
130156
ConsumerPlatformSQS = options.PlatformSQS
131157
)
158+
159+
// RabbitMQConfigWithDefaultTopicFanOutPattern returns a RabbitMQConsumerConfig with default configuration for topic fanout pattern.
160+
// It takes the queueName, exchangeName, and routingKeys as parameters and returns a pointer to RabbitMQConsumerConfig.
161+
// The default configuration includes a durable queue that is not auto-deleted, exclusive, and no-wait.
162+
// The queue is bound to the exchange with the provided routing keys.
163+
// the exchange is must be a fanout exchange. The exchange must be declared before using this configuration.
164+
// Read more about fanout exchange: https://www.rabbitmq.com/tutorials/amqp-concepts.html#exchange-fanout
165+
//
166+
// the routing keys can be in pattern format.
167+
// e.g. "a.*.b.#" will match "a.b", "a.c.b", "a.c.d.b", etc.
168+
// For more information on pattern matching, see https://www.rabbitmq.com/tutorials/tutorial-five-go.html
169+
func RabbitMQConfigWithDefaultTopicFanOutPattern(consumerChannel, publisherChannel *amqp.Channel,
170+
exchangeName string, routingKeys []string) *RabbitMQConsumerConfig {
171+
return &RabbitMQConsumerConfig{
172+
ConsumerChannel: consumerChannel,
173+
ReQueueChannel: publisherChannel,
174+
QueueDeclareConfig: &RabbitMQQueueDeclareConfig{
175+
Durable: true,
176+
AutoDelete: false,
177+
Exclusive: false,
178+
NoWait: false,
179+
Args: nil,
180+
},
181+
QueueBindConfig: &RabbitMQQueueBindConfig{
182+
RoutingKeys: routingKeys,
183+
ExchangeName: exchangeName,
184+
NoWait: false,
185+
Args: nil,
186+
},
187+
}
188+
}

0 commit comments

Comments
 (0)