5

I have an application which uses dynamic consumers. I'm using Spring Framework with RabbitMQ.

I have parameters like concurrentConsumers and maxConcurrentConsumers.

This is a example:

@Bean 
public SimpleMessageListenerContainer container(ConnectionFactory connection) {
    SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();

    container.setMaxConcurrentConsumers(8);
    container.setConcurrentConsumers(1);

    return container;
}

Can I change the values when the application is running? For example, if I want 5 maxConcurrentConsumers instead of 8, can I change the value on a terminal or something like this while the application is running?

Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
Maverick94
  • 227
  • 4
  • 15
  • 1
    Can't you use `@Value` annotation and define the values for `concurrentConsumers` and `maxConcurrentConsumers` in a property file, then expose a setter method to update these values at runtime? Please refer https://stackoverflow.com/questions/38761781/how-change-property-values-at-runtime-in-spring – FakirTrappedInCode Dec 12 '18 at 12:01
  • You can try to use `@RefreshScope` annotation with `@Value` example: [here](https://spring.io/guides/gs/centralized-configuration/), you need to add actuators and than you can change your properties file and call `/actuator/refresh` – Andrii Vdovychenko Dec 12 '18 at 12:04
  • 4
    Possible duplicate of [Can I replace a Spring bean definition at runtime?](https://stackoverflow.com/questions/4041300/can-i-replace-a-spring-bean-definition-at-runtime) – Mohsen Dec 12 '18 at 12:12
  • @FakirTrappedInCode but i have to stop the service, change the values in the property file and launch again. Did you mean this? – Maverick94 Dec 12 '18 at 12:52
  • @Spara yes but not. I just change these values `maxConcurrentConsumers` and `concurrentConsumers` at runtime. i think the link solution is a little complex. – Maverick94 Dec 12 '18 at 13:25
  • as the link said you can change `maxConcurrentConsumers` at runtime and it will refresh the value in spring context for you – Mohsen Dec 12 '18 at 13:26

1 Answers1

1

Your bean is a singleton and should be stateless (at least, immutable or effectively stateless) to ensure thread-safety and correctness.

As a rule, you should use the prototype scope for all stateful beans and the singleton scope for stateless beans.

Spring documentation

Sometimes, the creation of a bean is quite expensive, so it's more reasonable to construct an instance once and then guarantee that all possible changes made on this object will be permeated in a safe and correct fashion over all its consumers.

I advise building a simple event-driven mechanism.

There are

  • a MessageListenerContainerEvent extends ApplicationEvent which represents the changes made to the MessageListenerContainer bean;
  • a MessageListenerContainerChanger implements ApplicationListener<MessageListenerContainerEvent> who is the one listener who modifies the state of the bean, and guarantees that everything works properly;
  • other listeners who are class that use the bean and are interested in keeping it up-to-date. It's not necessary to send the changes to bean consumers, you could just notify them with no message. For them, it means that some properties of the bean they use locally might be out-of-date.
  • a publisher which could be an HTTP endpoint, or a @ShellMethod.

It might look too complex, you always can simplify it to

// somewhere in your code
synchronized(bean) {
    bean.setConcurrentConsumers(10);
}

but bear in mind the correctness this snippet propagates.

Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142