When deploying my microservice on spring cloud dataflow I get the following log:
No bean named 'errorChannel' has been explicitly defined. Therefore, a default PublishSubscribeChannel will be created
how do I direct error flows?
My guess is to create an errorChannel bean (as the message says). But I did not find any docs about it nor sample usages.
For example, I have a sink that executes an Insert on a database and want to direct it elsewhere if insert fails.
The default errorChannel bean has a LoggingHandler subscribed to it.
If you define your own errorHandler channel, it won't get the default LoggingHandler.
The error channel is automatically wired in.
Each consumer (or #StreamListener) gets a dedicated error channel binding.group.errors which is bridged to the global errorChannel.
You can add a #ServiceActivator to consume ErrorMessages from either of these channels.
Error channels are not applied on the producer side; you have to catch the exception yourself.
Related
I have a spring integration application and I am using message driven channel adapter for consuming the messages. This is the definition of the adapter -
<jms:message-driven-channel-adapter id="messageAdapter" destination="inQueue"
connection-factory="connectionFactory"
error-channel="errorChannel"
concurrent-consumers="${consumer.concurrent-consumers}"
acknowledge="transacted"
transaction-manager="transactionManager"
channel="channel"
auto-startup="true"
receive-timeout="50000"/>
So this message goes to my core channel and then goes through a series of service activators. In between if there is a error than this message is moved to errorChannel where I handle the errors and decide on what needs to be done with this message. For one scenario I want the message to not rollback to the queue, is it possible? I am using 'transacted' in my adapter definition so I am not sure how to drive this behaviour. Any help is greatly appreciated!
You don't describe what the transactionManager bean is. If it's a JmsTransactionManager, remove it and the container will just use local transactions.
Then, the transaction will only roll back if the flow on the error-channel throws an exception. If that error flow exits normally ("consuming" the error), the transaction will not roll back.
If it's some other transaction manager (e.g. JDBC) then remove it and start the JDBC transaction later in the flow (i.e. don't synchronize the JMS and JDBC transactions; again using a local JMS transaction).
How to publish exception in error-channel whenever we encounter any exception in any of the route. We dont want to catch exception manually. It should automatically routed to error-channel?
No, it can't go automatically to the error-channel. That's not how plain Java works. So, if you call some java code you expect an exception from there and you definitely use a try...catch construction.
The error-channel makes sense only in the processes not started by end-users, some active processes like task executors and schedulers. For this purpose we indeed provide an error-channel hook do not let downstream error to disappear.
Another way to do a-la try...catch, but still send to the error-channel can be done via Messaging Gateway: https://docs.spring.io/spring-integration/docs/current/reference/html/messaging-endpoints-chapter.html#gateway-error-handling. This way the Framework wraps the whole flow to the try...catch and sends an ErrorMessage to the configured errorChannel.
Also for per-service purpose we provide an ExpressionEvaluatingRequestHandlerAdvice with its own in-scope failureChannel: https://docs.spring.io/spring-integration/docs/current/reference/html/messaging-endpoints-chapter.html#expression-advice
I would like process the message programmatically using message-driven-channel-adapter. Here is scenario which I have to implement:
My application during the startup read the configuration from a service. The configuration provides information about the queues which will contain the messages. Hence I would like to create a message-driven-channel-adapter for each queue to listen to messages asynchronously.
Any example which initializes all the spring integration context programatically instead of using XML will be useful.
If you are going to do everything programmatically, I'd suggest you bypass Spring Integration magic and just use DefaultMessageListenerContainer directly.
Afterwards you can send messages to an existing MessageChannel directly from the MessageListener implementation or using Messaging Gateway.
Please, be careful with programmatic configuration with that do not miss important attributes like ApplicationContext or invocation for afterPropertiesSet().
We use an <int-amqp:publish-subscribe-channel/> as a kind of an event bus in our service-based application. The send method as well as the message handler are based on the Message class from spring-messaging (as of spring-integration 4.0 (+). Events are changes to entities that need to be picked up by other services.
The problem is: the spring-messaging Message class is treated as arbitrary object payload by spring-amqp as it is not recognized as a spring-amqp Message. This causes the following problems:
default message format is serialized Java objects. spring-amqp does not only serialize our original payload object only, but also the wrapping spring-messaging Message, which is not compatible between Spring Framework 4.0 and 4.1
configuring a message converter for JSON (Jackson2JsonMessageConverter to be exact) doesn't solve the problem, as it also converts the Message instance - which is spring-integration's GenericMessage, and that can't be instantiated from JSON as it lacks an appropriate constructor
We need to mix Spring versions, as we have services implemented with Grails 2.4 (based on Spring 4.0) and with current Spring Boot (relies on Spring 4.1).
Is there any way out of this, preferably an idiomatic spring-integration way? Is there maybe another abstraction instead or in addition to the PublishSubscribeAmqpChannel? Or any other means of message conversion that we could apply?
Instead of using an amqp-backed channel, use an outbound-channel-adapter to send and an inbound-channel-adapter to receive.
The channel holds the entire message (serialized) whereas the adapters transport the payload as the message body and (optionally) map headers to/from amqp headers.
You will need to configure a fanout exchange for pub/sub (the channel will create one called si.fanout.<channelName> by default. You can then bind a queue for each recipient.
I have a requirement to fetch jms message from IBM MQ. But the messages should be fetched only when required, say when a method is invoked. The picked up message need to be put to another queue in turn. That is , this scenario is for copying message from one queue to another when required.
How could I achieve this in Spring Integration.
I believe i could create a flow using inbound-channel-adapter, set to poll message at regular interval, along with outbound-channel-adapter. But with this, I could not pick the message as and when required.
Please advise.
Question updated:
1) While searching on the web to implement the suggested solution, I stepped on the spring documentation for JmsDestinationPollingSource saying - "This source is only recommended for very low message volume".
2) Since we need for high volume environment and in need of local transaction, I looked into the suggested JmsMessageDrivenEndpoint solution which looked like using MessageDrivenChannelAdapter. Can you please adviseas how i could proceed.
3) Also, in that case how can i detect if all messages have been read to stop the listener . Please advise
Question updated:
I am able to invoke start and stop on DefaultMessageListener container used with MessageDrivenChannelAdapter.
Can you also please advise as how I could find when there are no messages on the queue or when the queue is empty so that I could invoke stop.
Question updated:
Thanks Gary. Sorry for the late update.
To find when the queue becomes empty, can we override noMessageReceived method of DefaultMessageListenerContainer (inherited from AbstractPollingMessageListenerContainer) and invoke stop on the DMLC. This kind of solution is given in
Spring integration inbound-gateway Fire an event when queue is empty.
I thought this might be easier to implement. Please advise if it will be correct to do in that way.
Set auto-startup="false" on the inbound channel adapter (so it won't poll).
Get a reference to its MessageSource (either by #Autowire or otherwise injecting or context.getBean()). The bean name is adapterid.source and is of type JmsDestinationPollingSource.
Then invoke the receive() method.
Or you can just wire up a JmsDestinationPollingSource bean yourself without using the namespace support.