I am using an executor channel since I want to switch threads to finish the transaction at this point. The only other way to do this is a poller and I think the executor channel is a much nicer solution. The only problem is that I cannot find a way to define an error channel for this dispatcher. Errors are always published on the global errorChannel.
Here is my config:
<task:executor id="routingExec" pool-size="10"/>
<int:channel id="baseFlow.route">
<int:dispatcher failover="false" task-executor="routingExec"/>
</int:channel>
And I want to have something like this (like in the poller):
<task:executor id="routingExec" pool-size="10"/>
<int:channel id="baseFlow.route">
<int:dispatcher error-channel="myErrorChannel" failover="false" task-executor="routingExec"/>
</int:channel>
Errors are handled in the ExecutorChannel via ErrorHandlingTaskExecutor:
if (!(this.executor instanceof ErrorHandlingTaskExecutor)) {
ErrorHandler errorHandler = new MessagePublishingErrorHandler(
new BeanFactoryChannelResolver(this.getBeanFactory()));
this.executor = new ErrorHandlingTaskExecutor(this.executor, errorHandler);
}
Where defaultErrorChannel is really like IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME.
So, to use your own channel for error from that ExecutorChannel, you should use errorChannel header for each message to send, or just inject your own ErrorHandlingTaskExecutor with MessagePublishingErrorHandler and defaultErrorChannel configured to your expectations.
Related
EDIT: Here is a gist showing my log. It appears that there is ReceiveMessage and then a preSend on inputChannel:
https://gist.github.com/louisalexander/04e7d95835521efdd15455c98075e2ea
Apologies for being so dense, but I can't seem to figure out how to properly make use of the sqs-message-driven-channel-adapter
In my context file, I am configuring it as such:
<int-aws:sqs-message-driven-channel-adapter
id="my-message-driven-adapter" sqs="sqs" queues="some-queue-of-mine"
max-number-of-messages="5" visibility-timeout="200" wait-time-out="10"
send-timeout="2000" channel="inputChannel" />
I observe that messages are properly making it into some-queue-of-mine (by removing the above bit of code and sending messages to the queue). I then restart my server, enabling the message driven adapter and I observe that all the messages are consumed from the queue, but where did they go? :-/
My expectation was that the messages would be funneled into a DirectChannel named inputChannel:
<int:channel id="inputChannel"/>
That I have a service-activator consuming from as follows:
<int:service-activator ref="myConsumer"
method='execute' input-channel="inputChannel" output-channel="outputChannel">
<int:request-handler-advice-chain>
...
</int:request-handler-advice-chain>
</int:service-activator>
But of course, I am never seeing myConsumer get invoked. I imagine my understanding of how the MessageProducer mechanism works is inadequate. Can someone please correct my thinking by providing a trivial example of XML wiring?
According to the Logs the message is consumed by the handler.AbstractMessageHandler (AbstractMessageHandler.java:115) - ServiceActivator for [org.springframework.integration.handler.MethodInvokingMessageProcessor#493f49cd]. Although that might be a fully different story.
SqsMessageDrivenChannelAdapter can be supplied with the errorChannel to handle downstream exceptions. By default it is only logged.
The message sent from that adapter is like:
return new GenericMessage<>(message.getBody(), new SqsMessageHeaders(messageHeaders));
Where that message.getBody() is String. See QueueMessageUtils.createMessage().
So, be sure that your service-activator accepts that String as a paylaod and not any other type.
I'm writing a file polling implementation and am trying to determine if I need to use a AcceptOnceFileListFilter.
The first step the FileProcessor will perform is to move the file to another directory.
Does the poller "batchFilePoller" use multiple threads when polling? Can a race condition occur where a file will be read by multiple threads? In this case I assume I need to use the AcceptOnceFileListFilter.
However if the poller is only using one thread from the pool.
Then if the file is moved before the next poll time and it succeeds I assume there is no posability of the file been processed twice?
<int-file:inbound-channel-adapter id="batchFileInAdapter" directory="/somefolder" auto-create-directory="true" auto-startup="false" channel="batchFileInChannel" >
<int:poller id="batchFilePoller" fixed-rate="6000" task-executor="batchTaskExecutor" max-messages-per-poll="1" error-channel="batchPollingErrorChannel" />
</int-file:inbound-channel-adapter>
<int:channel id="batchFileInChannel"/>
<int:service-activator input-channel="batchFileInChannel" >
<bean class="com.foo.FileProcessor" />
</int:service-activator>
<task:executor id="batchTaskExecutor" pool-size="5" queue-capacity="20"/>
The <int-file:inbound-channel-adapter> has prevent-duplicates option which is true by default and it is your case since you don't provide any other options which prevent prevent-duplicates to be true.
And yes: any polling adapter is multi-threaded, if you use fixed-rate. In this case the new polling task can be run before a finish of previous one.
Even if it will be a single-threaded (using fixed-delay), the AcceptOnceFileListFilter must be there, because a new polling task doesn't know if file has been processed or not. And it reads the same file again.
AcceptOnceFileListFilter is exactly for those cases when you don't like to read the same file one more time. You can overcome that with <int:transactional synchronization-factory=""/> for the <poller> of the <int-file:inbound-channel-adapter>:
<int:transaction-synchronization-factory id="txSyncFactory">
<int:after-commit expression="payload.delete()"/>
</int:transaction-synchronization-factory>
and PseudoTransactionManager.
More info you can find in the Spring Integration Reference Manual.
At the beginning of my flow I have a file inbound adapter which reads a directory periodically:
<int-file:inbound-channel-adapter id="filteredFiles"
directory="${controller.cycle.lists.input.dir}"
channel="semaphoreChannel" filename-pattern="*.xml">
<int:poller fixed-delay="3000"/>**
</int-file:inbound-channel-adapter>
When the SI workflow ends it never happens again. It seems the poller is dead and stops working.
There aren't any error messages in the log nor any warnings.
Channel configuration:
<int:channel id="semaphoreChannel" datatype="java.io.File"/>
Second configuration:
<int-file:inbound-channel-adapter id="filteredFiles"
directory="${controller.cycle.lists.input.dir}"
channel="semaphoreChannel" filename-pattern="*.xml">
<int:poller cron="0 * * * * *" />
</int-file:inbound-channel-adapter>
It does not make sense.
Since you use default settings for other <poller> options, you end up with:
public static final int MAX_MESSAGES_UNBOUNDED = Integer.MIN_VALUE;
private volatile long maxMessagesPerPoll = MAX_MESSAGES_UNBOUNDED;
That means the FileReadingMessageSource reads all files by provided pattern during the single poller cycle.
The poller doesn't stop to work, but there is nothing more in the directory to read.
Change to this max-messages-per-poll="1" and let us know how it is.
From other side you can switch on DEBUG logging level for the org.springframework.integration.endpoint.SourcePollingChannelAdapter and there will be a message in logs:
Received no Message during the poll, returning 'false'
Is there a way to specify an advice, like RequestHandlerAdvice, for QueueChannel's doSend method.
I have a Filter sending a data to a queue channel (with send-timeout of 0). When the queue is full, this throws an exception. I would want to trap this exception instead of throwing it to the sender.
<int:filter id="filterA" input-channel="channelA" output-channel="channelB"
method="fltrBsdOnCondtn" ref="fltr" send-timeout="0" />
<int:channel id="channelB">
<int:queue capacity="5000" />
</int:channel>
Thanks in advance!
Regards,
Satheesh
You could use a custom advice on the queue channel, using normal Spring AOP configuration.
But, it's probably easier to just put an error-channel on whatever is starting the flow (e.g. a <gateway/>) and handle the error there.
I'm struggling a lot with following scenario:
WS |============| JMS ~~~ async future processing ~~~
The idea is following. Incoming WS request is stored to JMS and once it is stored (correctly sent) the WS client is responded with OK.
I'm able to achieve that via spring jmsTemplate, something like
<chain>
<service-activator>
... calling jmsTemplate send ...
</service-activator>
<OK response>
</chain>
I don't want to use the jmsTemplate, however if I use the jms:outbound-channel-adapter, no reply message is generated and it gets stuck. Other constructions leads to synchronous processing, means that the WS response was delayed until the JMS request is fully processed.
I believe there is an easy solution, but I was't able to find it for hours. Thanks!
EDIT:
Suggested solution works, thanks a lot! Friend of mine recommended me another one - using wire-tap, it looks nice IMHO.
<int:gateway service-interface="MyService" default-request-channel="in"/>
<channel id="in">
<interceptors>
<wire-tap channel="inJms"/>
</interceptors>
</channel>
<channel id="inJms"/>
<transformer expression="'OK'" input-channel="in" order="1"/>
<jms:outbound-channel-adapter channel="inJms" destination="requestQueue"/>
The <publish-subscribe-channel/> helps you:
<publish-subscribe-channel id="storeMessageChannel"/>
<int-ws:inbound-gateway request-channel="storeMessageChannel"/>
<int-jms:outbound-channel-adapter channel="storeMessageChannel"/>
<int:transformer input-channel="storeMessageChannel" expression="'OK'"/>
Well, in this case the message from WS will be sent to the storeMessageChannel with two sequential subscribers: 1. JMS - to place message to the queue; 2. Simple transformer - to return to the WS response 'OK'.
Transformer will apply the message only after jms outbound adapter has done its work.