I need to be able to update the refreshInterval for JMS client programmatically.
I tried to do it through JmsConfiguration bean, but that's useless, and I couldn't find any configuration on the ActiveMQConnectionFactory class that I could use to update that value.
You can set the recoveryInterval property on the ActiveMQComponent/JmsComponent or set the same property on the JmsConfiguration POJO.
However, since the Camel ActiveMQ/JMS consumer is based on a Spring JMS listeners, like DefaultMessageListenerContainer, you cannot simply change that parameter during runtime (if that's what you intend). You need to set the recoveryInterval before the route is created. You can of course recreate the route and possibly ActiveMQ component and have the recovery interval set programmatically.
If you really need this feature, you can subclass DefaultMessageListenerContainer to allow setRecoveryInterval to actually trigger during runtime (not sure how easy that is, there is some thread handling to watch out for). Your custom MLC can be supplied to camel via the messageListenerContainerFactoryRef option.
Related
We have existing REST routes working with Camel 2.23.1 and jetty. We redirect incoming calls to an appropriate server based on the uri, query, and the user's authentication. We want to handle this more generally.
How can we modify the following code to handle any uri with "/say" as the prefix?
In our RouteBuilder:
RestConfigurationDefinition rConfig = restConfiguration()
.component("jetty")
.port(webserverPort)
.contextPath("/")
.bindingMode(RestBindingMode.off)
.enableCORS(true)
.dataFormatProperty("prettyPrint", "true");
rest("/say")
.get().to("direct:test");
from("direct:test")
.bean(RouteRest.class, "getTestURI(*,*)")
.to("mock:output");
We have tried adding a property to the restConfiguration, ala
.componentProperty("matchOnUriPrefix", "true");
We have tried adding the same property to the rest route definition, ala
rest("/bye?matchOnUriPrefix=true")
We have tried creating a new from statement, which seems to break everything, ala
from("jetty://0.0.0.0:8123/now?matchOnUriPrefix=true").to("direct:test");
I am aware of this question and answer, but don't know how to apply it to my case:
stackoverflow.com/questions/39341784
Further, is it possible to match some incoming calls with explicitly defined uri's, like "/admin/status", and all other uri's to "direct:test"?
We ended up taking out the restConfiguration() entirely and configuring endpoints individually, which fit our expanding requirements anyway. Our oritinal restConfiguration() was limiting the messages that could get to the endpoints themselves. Perhaps we could have modified the restConfiguration directly to enable greater flexibility, including removal of .contextPath("/"). This directly allowed the following code to work:
from("jetty:http://{{ip}}:{{port}}?matchOnUriPrefix=true")
.bean(RestForward.class, "checkUserAuth(*)")
.bean(RestForward.class, "checkDevice(*)")
.bean(RestForward.class, "forward(*,*)")
.to("mock:output");
Our configuration is: 1...n Message receivers with a shared database.
Messages should only be processed once.
#RabbitListener(bindings = #QueueBinding(
value = #Queue(value = "message-queue", durable = "true"),
exchange = #Exchange(value = TOPIC_EXCHANGE, type = "topic", durable = "true"),
key = MESSAGE_QUEUE1_RK)
)
public void receiveMessage(CustomMessage message) throws InterruptedException {
System.out.println("I have been received = " + message);
}
We want to to guarantee messages will be processed once, we have a message store with id's of messages already processed.
Is it possible to hook in this check before receiveMessage?
We tried to look at a MessagePostProcessor with a rabbitTemplate but didn't seem to work.
any advice on how to do this?
We tried with a MethodInterceptor and this works, but is pretty ugly.
Thanks
Solution found - thanks to Gary
I created a MessagePostProcessorInjector which implements SmartLifecycle
and on startup, I inspect each container and if it is a AbstractMessageListenerContainer add a customer MessagePostProccesser
and a custom ErrorHandler which looks for certain type of Exceptions and drops them (other forward to defaultErrorHandler)
Since we are using DLQ I found throwing exceptions or setting to null wouldn't really work.
I'll make a pull request to ignore null Messages after a MPP.
Interesting; the SimpleMessageListenerContainer does have a property afterReceivePostProcessors (not currently available via the listener container factory used by the annotation, but it could be injected later).
However, those postprocessors won't help because we still invoke the listener.
Please feel free to open a JIRA Improvement Issue for two things:
expose the afterReceivePostProcessors in the listener container factories
if a post processor returns null, skip calling the listener method.
(correction, the property is indeed exposed by the factory).
EDIT
How it works...
During context initialization...
For each annotation detected by the bean post processor the container is created and registered in the RabbitListenerEndpointRegistry
Near the end of context initialization, the registry is start()ed and it starts all containers that are configured for autoStartup (default).
To do further configuration of the container before it's started (e.g. for properties not currently exposed by the container factories), set autoStartup to false.
You can then get the container(s) from the registry (either as a collection or by id). Simply #Autowire the registry in your app.
Cast the container to a SimpleMessageListenerContainer (or alternatively a DirectMessageListenerContainer if using Spring AMQP 2.0 or later and you are using its factory instead).
Set the additional properties (such as the afterReceiveMessagePostProcessors); then start() the container.
Note: until we enhance the container to allow MPPs that return null, a possible alternative is to throw an AmqpRejectAndDontRequeueException from the MPP. However, this is probably not what you want if you have DLQs configured.
Throwing an exception extending from ImmediateAcknowledgeAmqpException from postProcessMessage() of DuplicateChecking MPP when message is duplicate will also not pass the message to the rabbit Listener.
Spring Integration's Gateway element has a "default-reply-timeout" attribute, but no way to set the timeout value based on data from the message itself. I can create a gateway for each possible timeout value and then select an appropriate gateway for that message during run-time, but that's obviously a nasty workaround.
Release 4.2 added a "remote-timeout-expression" attribute to TCPOutboundGateway, but that change didn't make it to the GatewayProxyFactoryBean.
That being said, is there a way to configure timeouts on a message-specific basis? If not, Is the "remote-timeout-expression" attribute planning on being ported to the GatewayProxyFactoryBean at some point?
Thanks for any help!
It's currently a fixed value and not configurable on a message-by-message basis.
We can certainly consider making it so but it would likely not make it into 4.3, since the release candidate is already out.
One possible work-around would be use MessagingTemplates instead of a gateway. You could set up a collection of MessagingTemplates, each configured with a different timeout, instead of the gateway:
Foo result = this.templateWith10SecondTimeout.convertSendAndReceive(bar, Foo.class);
Alternatively, you can add different methods to your gateway, each with a different reply timeout.
public interface GW {
Foo waitTenSeconds(Bar bar);
Foo waitTwentySeconds(Bar, bar);
}
The default timeout is a default, the timeout can be set on each method.
Is it possible to re-read custom key/values from consul k/v store with spring-cloud-consul lib? Haven't found an answer in documentation.
Of course it can be accessed with http GET request, but the point is to change some key's value and to make spring application to handle this change immediately.
UPD: unfortunately we've migrated from Consul to config-server, but I guess #RefreshScope should do the magic.
spring-cloud-consul auto configures a ConsulClient into the application context. This if from the Ecwid/consul-api client. Usage is the same, but instead of calling new ConsulClient() you would inject one (ie #Autowired ConsulClient consulClient).
My application is running under Tomcat with a number of Spring's DefaultMessageListenerContainer listening to a number of different JMS queues running under Oracle 11g Weblogic server.
DefaultMessageListenerContainer configuration is.. well.. default with sessionTransacted = false and sessionAcknowledgeMode = AUTO_ACKNOWLEDGE. The type of messages my application receives is javax.jms.TextMessage. The actual body of the message (message.getText()) is an XML string.
I was faced with a problem when a number of application instances (dev boxes, test boxes, etc) needed to be pointed to the same JMS server, so once message comes to the queue it is unknown which server will consume it (I believe the one that runs receive() method first). The problem is that any given application instance is only interested in messages dedicated to that particular application instance, so with a current configuration most of the messages get lost (consumed by other application instances and ignored in message processing business logic).
I have no control on JMS server implementation, but I can force it to set a particular XML element in the message body to an application instance specific value, so I can read it and decide what application instance should consume it.
The most natural way to do that would be setting messageSelector property on DefaultMessageListenerContainer so decision is made on JMS server which consumer should receive what message. I also learned about Weblogic specific JMS_BEA_SELECT message selector expression that works with XML message types. Unfortunately it doesn't seem to work with javax.jms.TextMessage messages with XML payload (or at least I couldn't make it to work). I was trying the following expression with no luck:
<property name="messageSelector" value="JMS_BEA_SELECT('xpath', '//Event/CorrelationID/text()') = 'MY_SELECTOR_TEST_3'"/>
According to this article the other options are:
Use a transacted session, then rollback the session so the message will go back to the queue and can be consumed by other application instance.
Use Session.CLIENT_ACKNOWLEDGE when creating a session, then recover the session so the message will go back to the queue and can be consumed by other application instance.
I understand that I need to set sessionTransacted and sessionAcknowledgeMode on DefaultMessageListenerContainer to non-default values (what values?) and then rollback the session in the message processor code (option 1) or don't call message.acknowledge() (option 2).
It looks like DefaultMessageListenerContainer controls message processing / session life cycle. How can I customise it?
Solution with rollbacks looks really weird.
Setting message selector should be enough. I didn't work with BEA JMS implementation but i guess you can take care with regular "SELECT" and selecting from header .
<property name="messageSelector" value="CorrelationID='MY_SELECTOR_TEST_3'/>
Do you work on both side of communication points (server,client) to control correlation id?