Announcement Announcement Module
Collapse
No announcement yet.
Connecting to two machines from spring AMQP Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Connecting to two machines from spring AMQP

    I have a situation where i need to connect to two hosts. I setup two separate configuration classes , with different connections and queue declarations and bindings.

    have

    <context:component-scan base-package="com.xx.tdb.queue_processor.config1,com.xx x.tdb.queue_processor.config2"/>

    entry in my spring config file. AMQP always seems to load and initialize only one of the config classes.None of the auto wiring init is happening in the other config class. what am i doing wrong?


    Thanks in advance,
    Suresh

  • #2
    Are you providing distinct bean names for the results of your @Bean-annotated methods?

    Comment


    • #3
      u mean methods like

      @Bean
      public Queue eventQueue() {
      return new Queue(queueName);
      }

      @Bean
      public DirectExchange tdbExchange() {
      return new DirectExchange(exchangeName);
      }

      /**
      * Binds to the TDB data exchange. Interested in any events.
      * @return binding object
      */
      @Bean
      public Binding tdbDataBinding() {
      return BindingBuilder.from(
      eventQueue()).to(tdbExchange()).with(routingKey);
      }



      shd these be distinct ?

      Comment


      • #4
        Dumb , got it

        thanks for your help

        Comment


        • #5
          Have you verified that and got it working correctly now?

          I should have explained it in a bit more detail...

          The method names become bean names, and the behavior is similar to the use of bean IDs within XML files. They must be unique within a single ApplicationContext so if there is overlap, the last bean definition registered will replace any existing bean with the same ID/name.

          Hope that helps.
          -Mark

          Comment


          • #6
            Thanks Mark, yeah got that.

            Still facing an issue, I have two consumers connecting to two hosts.
            host1 and host2, I have two java config classes RabbitMqConfiguration1 and RabbitMqConfiguration2. The only difference is they both connect to a different host. When i try to start the listeners , I keep getting a queue not declared error in one of them. When i debug i do see both the bindings getting registered to the correct hosts in both the config classes.

            the error i get is as follows

            Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; reason: {#method<channel.close>(reply-code=404,reply-text=NOT_FOUND - no queue 'LWESEvents' in vhost 'TDB-Dev',class-id=50,method-id=10),null,""}



            when I start them by pointing them to the same host, either 1 or 2 then it works.

            @Bean(name = "eventQueue2")
            public Queue eventQueue() {

            }

            @Bean(name = "tdbExchange2")
            public DirectExchange tdbExchange() {
            }

            @Bean(name = "tdbDataBinding2")
            public Binding tdbDataBinding() {
            }

            @Bean(name = "messageListenerContainer2")
            public SimpleMessageListenerContainer messageListenerContainer() {
            }

            @Bean(name = "connectionFactory2")
            public ConnectionFactory connectionFactory() {
            //only host differs here rest of all the params are same
            }

            @Bean(name = "messageListenerAdapter2")
            public MessageListenerAdapter messageListenerAdapter() {
            }

            thanks again for your help
            Suresh

            Comment


            • #7
              Ahh!! its cause the amqpAdmin was a singleton.

              I fixed it by not implementing from AbstractRabbitConfiguration and providing my own adminbean

              @Bean(name = "amqpAdmin1")
              public AmqpAdmin amqpAdmin() {
              return new RabbitAdmin(rabbitTemplate());
              }

              @Bean(name = "template1")
              public RabbitTemplate rabbitTemplate() {
              return new RabbitTemplate(connectionFactory());
              }

              Is there a better way to do this, I see that the BIndings are registered for each of the admins twice, its ok in my case as everything except the host is the same.

              thanks,
              Suresh
              Last edited by avyaktha; Oct 8th, 2010, 06:01 PM.

              Comment


              • #8
                any one , have any suggestions?

                Comment


                • #9
                  Hi,

                  We should more explicitly support this type of scenario. What I can suggest is to either set autoStartup to false in RabbitAdmin or avoid its use completely so that it doesn't perform any of the declarations and instead do it yourself in code. Not ideal. Perhaps a better short term approach is to subclass RabbitAdmin and override the start method so that only the Exchange,Queues, and Bindings specific to a given broker/connection will be used. Instead of the current code that get all the queues, i.e.
                  Code:
                  applicationContext.getBeansOfType(Queue.class).values();
                  It would instead use a lookup method that uses qualifier annotations to restrict the set of returned beans.

                  Code:
                  getBeansWithAnnotation(Class<? extends Annotation> annotationType)
                  comes close but one would also like to specify the class... a getBeanOfTypeWithAnnotation method.... Otherwise you will have to filter out from the returned map the beans which are queues, exchanges, bindings...

                  The @Configuration bean definitons would then have the qualifier annotation on them.

                  Code:
                  @Bean(name = "eventQueue2")
                  @Qualifier("broker2")
                  public Queue eventQueue() {
                  }
                  I don't think there is 'inheritance' of qualifier annotations on the @Configuration class to the methods, but that might be nice to consider.

                  Then one would need two instances of this subclass of RabbitAdmin, each configured to use different qualifier annotations.

                  HTH,
                  Mark
                  Last edited by Mark Pollack; Oct 13th, 2010, 01:20 PM.

                  Comment


                  • #10
                    Maybe two ApplicationContext instances, one for each host would help?

                    Multiple vhosts is something we should support eventually (and Holly said she was interested in contributing in this area), so it will be useful to keep this discussion going. Open a JIRA or two maybe?

                    Comment


                    • #11
                      We do indeed need to handle scenarios where an installation (Erlang/Rabbit) has multiple nodes and for each node we can have multiple virtual hosts and then the fun begins. For the moment Mark Pollack's suggestion works with @Qualifier. That said, this does not allow for an application to dynamically adapt to newly-created virtual hosts > exchange, queues, etc in runtime. I'm working on this but it's a prototype.

                      I have definitely seen
                      Code:
                      Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; reason: {#method<channel.close>(reply-code=404,reply-text=NOT_FOUND - no queue 'LWESEvents' in vhost 'TDB-Dev',class-id=50,method-id=10),null,""}
                      You simply don't have the right queue and vhost matched up as it says. If you need to initialize it once you can create it in your configuration with

                      Code:
                      @Bean
                      public RabbitBrokerAdmin rabbitBrokerAdmin() {
                      //create the admin and then declare the queue
                      }
                      Note that if you are using that queue as the main queue in your SimpleMessageListenerContainer bean, you will need to insure that queue exists in the node's virtual host prior to creation of the listener.

                      And with these
                      Code:
                      @Bean(name = "eventQueue2")
                      public Queue eventQueue() {
                      }
                      Because the name 'eventQueue' becomes the bean name, you don't need name="", simply
                      Code:
                      @Bean
                      public Queue eventQueue2() {
                      }
                      - Holly

                      Comment

                      Working...
                      X