6

I've created using the RabbitMQ web-UI a topic exchange TX and bind to the exchange two queues TX.Q1 and TX.Q2, each binded with routing-keys rk1 and rk2 accordingly, and produced few messages to the exchange.

Now I want to create a consumer using Spring Cloud Stream that will take messages from Q1 only. I tried using configuration:

spring.cloud.stream.bindings.input.destination=TX
spring.cloud.stream.bindings.input.group=Q1

and the annotation @StreamListner(Sink.INPUT) for the method that consumes messages.

As result I can see that the consumer has created a queue (or binding) with the same name TX.Q1 but the Routing-Key of the new queue/bind is #.
How can I configure via Spring Cloud Stream a consumer that will consume messages from the predifined queue (only that routed with rk1).

Yuval Simhon
  • 1,439
  • 2
  • 19
  • 34

4 Answers4

5

So for now, the work-around that Garry Russell suggested has solved the issue for me.

I've used @RabbitListener instead of @StreamListenet this way:
@RabbitListener(bindings = @QueueBinding(value = @Queue(value = "TX.Q1", durable = "true"), exchange = @Exchange(value = "TX", type = "topic", durable = "true"), key = "rk1").

As a result, the predefined queue TX.Q1 is bind with binding key : rk1 to the exchange TX.

Waiting for updates on the Spring Cloud Steream issue.

Yuval Simhon
  • 1,439
  • 2
  • 19
  • 34
  • 1
    It's being a while since this workaround, I'm wondering if you came out with a more clean solution (e.g. using properties instead of annotations). – iakko Jan 10 '19 at 11:32
3

I think I found the solution using the @StreamListener, not using the workaround. Everything is made in the configuration, not in the code.

The configuration I used is the following (it's in .yml, but you can easly translate it in .properties):

spring:
  cloud:
    stream:
      bindings:
        input:
          binder: <binder_name>
          destination: TX
          group: Q1
      binders:
        <binder_name>:
          type: rabbit
          environment:
            spring:
              rabbitmq:
                host: <host>
                port: <port>
                virtual-host: <vhost>
                username: <username>
                password: <password>
      rabbit:
        bindings:
          input:
            consumer:
              binding-routing-key: rk1
              exchange-name: TX
              queue-name-group-only: true
              bind-queue: true
              exchange-durable: true
              exchange-type: topic

Using this approach, you don't have to write a particular code to let the RabbitMQ consumer connect to your cluster, this should solve your case.

Hope this helps.

iakko
  • 508
  • 2
  • 5
  • 18
  • it doesn't work as expected. For instance, I exactly gave the above settings but each time I restart my application, I notice that in RabbitMQ a new binding gets created with routing key # - even though I had already defined another routing key. So, whenever I sent a message even without routing key - I am not expecting my listener to get that message - however, as a new binding got automatically created (#) as mentioned in original question as well - I am unable to send message with specific routing key. – Neeraj Singh Mar 04 '19 at 01:21
0

Spring Cloud Stream sets the router key internally for the consumer endpoint to be either the destination name (exchange name) itself or the routing based on the partition header in case of static partitioning.

I think this github issue might be relevant to your case.

Ilayaperumal Gopinathan
  • 4,099
  • 1
  • 13
  • 12
  • So you mean that with Spring cloud stream I can't bind a consumer to specific predefined (not anonymous) queue that has a routing key? – Yuval Simhon Dec 13 '16 at 14:58
  • 1
    I just tested and we add a second binding; I think that's a bug - if the queue already exists we should not add the generic (`#` wildcard binding). As a work-around, you could use a `@RabbitListener` instead of a `@StreamListener` (unless you are relying on the stream listener for conversion). I opened [and issue for this](https://github.com/spring-cloud/spring-cloud-stream-binder-rabbit/issues/34). – Gary Russell Dec 13 '16 at 15:19
0

It is encouraged to use this property under consumer to enable rabbit to consume from existing queue. Please note that the queue name will be picked from the group property only and not from destination.

queueNameGroupOnly: true

Example:

cloud:
stream:
  # rabbit setting: https://github.com/spring-cloud/spring-cloud-stream-binder-rabbit
  rabbit:
    bindings:
      input:
        consumer:
          acknowledgeMode: AUTO
          bindingRoutingKey: DECISION_PERSISTENCE_KEY
          declareExchange: false
          bindQueue: false
          queueNameGroupOnly: true
          consumerTagPrefix: dpa-rabbit-consumer
  bindings:
    input:
      binder: rabbit
      group: DECISION_PERSISTENCE_QUEUE
      content-type: application/json
Shivankur Pal
  • 163
  • 2
  • 9