I'm consuming messages with spring-integration-kafka, using a message-driven-channel-adapter:
<int-kafka:message-driven-channel-adapter
id="kafkaListener"
listener-container="container1"
channel="outputFromKafka"
error-channel="errorChannel"/>
The container uses a JsonDeserializer to deserialize the incoming JSON to an object:
<beans:bean id="container1" class="org.springframework.kafka.listener.KafkaMessageListenerContainer">
<beans:constructor-arg>
<beans:bean class="org.springframework.kafka.core.DefaultKafkaConsumerFactory">
<beans:constructor-arg>
<beans:map>
<beans:entry key="bootstrap.servers" value="localhost:9092" />
<beans:entry key="key.deserializer" value="org.apache.kafka.common.serialization.StringDeserializer" />
<beans:entry key="group.id" value="mygroup" />
</beans:map>
</beans:constructor-arg>
<beans:property name="valueDeserializer">
<beans:bean class="org.springframework.kafka.support.serializer.JsonDeserializer">
<beans:constructor-arg value="com.foo.MyType"/>
</beans:bean>
</beans:property>
</beans:bean>
</beans:constructor-arg>
<beans:constructor-arg>
<beans:bean class="org.springframework.kafka.listener.config.ContainerProperties">
<beans:constructor-arg name="topics" value="foo" />
</beans:bean>
</beans:constructor-arg>
</beans:bean>
If the message can't be parsed successfully (e.g. because the consumer accidentally uses the wrong type), an exception is thrown:
ERROR org.apache.kafka.clients.NetworkClient - Uncaught error in request completion: org.apache.kafka.common.errors.SerializationException: Can't deserialize data ...
After this, the adapter is receiving the same message again (probably because the last one wasn't committed?), and fails in exactly the same way, resulting in an endless stream of exceptions.
It looks like the configured error-channel is not used.
What are the options to handle errors like this, and how is it configured in XML?
It looks like the configured error-channel is not used.
What makes you believe that?
I just ran a test with the error channel set to errorChannel (the default, with a logging adapter)...
12:06:08.366 [container-kafka-consumer-1] ERROR o.s.i.handler.LoggingHandler - ...
Can you provide a debug log snippet for org.springframework.integration showing a failure?
EDIT
Oh, sorry...
ERROR org.apache.kafka.clients.NetworkClient - Uncaught error in request completion: org.apache.kafka.common.errors.SerializationException: Can't deserialize data ...
That's much lower down in the stack before Spring Integration gets the message.
Related
I have registered an AsyncHandler and also added a success-channel to an SQS outbound flow. The success-channel has a int:logging-channel-adapter endpoint. However I am not able to see any logs from this adapter. The AsyncHandler is able to receive the call-backs but nothing on the success-channel.
In the SqsMessageHandler I see that we are setting an output channel in the obtainAsyncHandler method, but I did not see the success-channel set anywhere. Am I missing something?
I would prefer using the success and failure channels and not AsyncHandler call-back Impl to avoid having AWS specific code in my classes.
Also my <int-aws:sqs-outbound-channel-adapter> is inside a <int:chain> which has no output channel, since the flow ends when the message is sent.
EDIT - Added Config
This is the only way I can get it to log the callback.
<int:channel id="chainChannel" />
<int:channel id="successChannel" />
<bean class="ServiceTransformer" id="serviceTransformer" />
<int:chain input-channel="serviceChannel" id="sendToServiceSqsChain" output-channel="chainChannel">
<int:transformer ref="serviceTransformer" method="transform" />
<int:header-filter header-names="config" />
<int-aws:sqs-outbound-channel-adapter sqs="amazonSQS" queue="some-queue" async-handler="sqsPublishCallbackHandler" success-channel="successChannel"/>
</int:chain>
<int:logging-channel-adapter log-full-message="true" channel="chainChannel" />
Here I can just use the same channel in both chain (outbound channel) and sqs-outbound (success-channel)
Unable to get it to work like below:
<int:channel id="successChannel" />
<bean class="ServiceTransformer" id="serviceTransformer" />
<int:chain input-channel="serviceChannel" id="sendToServiceSqsChain" >
<int:transformer ref="serviceTransformer" method="transform" />
<int:header-filter header-names="config" />
<int-aws:sqs-outbound-channel-adapter sqs="amazonSQS" queue="some-queue" async-handler="sqsPublishCallbackHandler" success-channel="successChannel"/>
</int:chain>
<int:logging-channel-adapter log-full-message="true" channel="successChannel" />
The <int-aws:sqs-outbound-channel-adapter> component is one-way, therefore there is no outputChannel option expose. However the target class is AbstractMessageProducingHandler. To avoid code duplication we reuse an existing outputChannel internally for that AsyncHandler.
In the XML parser we just remap one to another:
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "success-channel", "outputChannel");
You probably don't see anything in logs because you need to adjust logging config respectively for the appropriate category and level.
UPDATE
According my testing this is definitely not possible to configure such a component with XML DSL within the <chain>. That <int-aws:sqs-outbound-channel-adapter> has to be presented outside of the <chain>.
Consider to more your configuration to Java DSL instead: https://docs.spring.io/spring-integration/docs/5.3.2.RELEASE/reference/html/dsl.html#java-dsl.
I am new to spring integration and we have created an SI flow where we have Splitter and Aggregator also recipient-list-router and Aggregator.
Today, while checking a code I got confused about how Aggregator will clean its store if we have an exception in between flow.
I am worried about the scenario where we got an exception between the flow and that creates stale state object in the system.
I have checked the spring integration doc but no luck (https://docs.spring.io/spring-integration/docs/2.0.0.RC1/reference/html/aggregator.html).
I can see only one topic "Managing State in an Aggregator: MessageGroupStore" but that is for "application shots down".
Also, I did google for the same and I found one thread https://dzone.com/articles/spring-integration-robust but not able to folow much. Sure, I will come back if I am able to find some solution.
I am using OOB Splitter, recipient-list-router and Aggregator. Considering pattern should have mechanism handle this common scenario.
Can you please guide me
i.e:
<int:recipient-list-router input-channel="inputChannel"
default-output-channel="nullChannel">
<int:recipient channel="aInputChannel" />
<int:recipient channel="bInputChannel" />
</int:recipient-list-router>
<int:service-activator ref="aHandler"
input-channel="aInputChannel" output-channel="aggregatorOutputChannel" />
<!-- we have exception in the bHandler -->
<int:service-activator ref="bHandler"
input-channel="bInputChannel" output-channel="aggregatorOutputChannel" />
<int:aggregator input-channel="aggregatorOutputChannel"
output-channel="outputChannel" />
OR
<int-file:splitter id="splitile"
charset="UTF-8" apply-sequence="true" iterator="false"
input-channel="inputChannel"
output-channel="bTransformerChannel" />
<!-- consider we have exception at 4th chunk -->
<int:service-activator ref="transform"
input-channel="bTransformerChannel" output-channel="aggregatorOutputChannel" />
<int:aggregator input-channel="aggregatorOutputChannel"
output-channel="outputChannel" />
Yes; the aggregator is a "passive" component by default - all actions are taken when a message arrives.
To time out stale groups you can use a reaper or, with more recent versions, a group-timeout.
I have written code to read message from IBM MQ using Spring Integration JMS-message-driven-channel-adapter but not able to read message from queue can anybody help me out below is my configuration.
<beans:bean id="ibmJmsConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
<beans:property name="transportType" value="1"/>
<beans:property name="queueManager" value="***"/>
<beans:property name="hostName" value="**"/>
<beans:property name="port" value="**" />
<beans:property name="channel" value="***"/>
</beans:bean>
<beans:bean id="receiverQueue" class="com.ibm.mq.jms.MQQueue">
<beans:constructor-arg index="0" value="****"/>
<beans:constructor-arg index="1" value="****"/>
</beans:bean>
<integration:channel id="componentInfoChannel" />
<jms:message-driven-channel-adapter
id="componentInfoAdapter" connection-factory="ibmJmsConnectionFactory" destination="receiverQueue" channel="componentInfoChannel"
/>
<integration:service-activator id="componentInfoActivator"
input-channel="componentInfoChannel" ref="componentInfoConsumer"
method="componentInfoListen" />
Above configuration is working but failing when I added logging adapter its continously printing warning on console .Detail are mention below .
<integration:logging-channel-adapter
id="componentInfologger" level="INFO" />
<integration:wire-tap id="componentInfoWireTap"
channel="componentInfologger" pattern="*" order="2" />
<integration:logging-channel-adapter
id="logger" log-full-message="true" level="INFO" />
2017-02-23 00:09:05.093 WARN [componentdatafiles,48f69e84ab395754,ebf4ae7f3b812a01,false] 90072 --- [ter.container-1] o.s.j.l.DefaultMessageListenerContainer : Execution of JMS message listener failed, and no ErrorHandler has been set.
java.lang.StackOverflowError: null
at java.util.Collections$SynchronizedMap.put(Unknown Source)
at ch.qos.logback.classic.util.LogbackMDCAdapter.put(LogbackMDCAdapter.java:110)
at org.slf4j.MDC.put(MDC.java:147)
at org.springframework.cloud.sleuth.log.Slf4jSpanLogger.logStartedSpan(Slf4jSpanLogger.java:48)
at org.springframework.cloud.sleuth.trace.DefaultTracer.createChild(DefaultTracer.java:170)
at org.springframework.cloud.sleuth.trace.DefaultTracer.createSpan(DefaultTracer.java:72)
at org.springframework.cloud.sleuth.instrument.messaging.TraceChannelInterceptor.startSpan(TraceChannelInterceptor.java:98)
at org.springframework.cloud.sleuth.instrument.messaging.TraceChannelInterceptor.preSend(TraceChannelInterceptor.java:78)
at org.springframework.integration.channel.AbstractMessageChannel$ChannelInterceptorList.preSend(AbstractMessageChannel.java:538)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:415)
at org.springframework.integration.channel.interceptor.WireTap.preSend(WireTap.java:168)
at org.springframework.integration.channel.AbstractMessageChannel$ChannelInterceptorList.preSend(AbstractMessageChannel.java:538)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:415)
at org.springframework.integration.channel.interceptor.WireTap.preSend(WireTap.java:168)
at org.springframework.integration.channel.AbstractMessageChannel$ChannelInterceptorList.preSend(AbstractMessageChannel.java:538)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:415)
at org.springframework.integration.channel.interceptor.WireTap.preSend(WireTap.java:168)
at org.springframework.integration.channel.AbstractMessageChannel$ChannelInterceptorList.preSend(AbstractMessageChannel.java:538)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:415)
at org.springframework.integration.channel.interceptor.WireTap.preSend(WireTap.java:168)
Sorry for delay. So, I guess your id="logger" is redundant component. And the problem is exactly with the <integration:wire-tap> and combination with the TraceChannelInterceptor.
I mean that you use here Spring Cloud Sleuth.
Would you mind sharing DEBUG for the org.springframework.integration category meanwhile I'm trying to reproduce an issue locally.
Plus you can exclude componentInfologger from the tracing to avoid that java.lang.StackOverflowError.
I think it happens somehow that we loop tracing via wire-tap.
Currently am working with spring integration for new application and started poc to know how to handle the failure cases.
In my application spring integration will receive message from IBM mq and validate the header information and route to different queue depends on the message type. incoming message could be bulk message, so i've used splitter and aggregator from spring integration and am having good progress and control over the technical workflow.
Currently am facing few issues, we have IBM mq and also webservice as our gateway. Both gateway receive the message and send to splitter channel where splitter splits the message and send to outbound channel( executor channel). so message will be send to destination in parallel and status update service activator will receive the message with same channel with order=2 and send to aggregator. so for its good with implementation.
Problem:
if jms outbound gateway throws the execption i've added advise as exception handler which wil send to another service activator to update failure status to DTO object and will have same aggregator channel as output but am not receiving the message in aggregator channel in this case and aggregator receive only in happy flow.
I want to aggregate the outbound successful message and failure message(other service activator update the status) and then the complete status needs to posted to response queue as another outbound or as response in webservice.
i tried to have ordered succesful service activator and failure error handler service activator to have same channel which is input channel for aggregator and its not working.
Appreciated for your guidance to proceed with this workflow
using Spring Integration 2.2.2
<channel id="inbound"/>
<channel id="splitterInChannel"/>
<channel id="splitterOutChannel">
<dispatcher task-executor="splitterExecutor"/>
</channel>
<beans:bean id="splitterExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<beans:property name="corePoolSize" value="5" />
<beans:property name="maxPoolSize" value="10" />
<beans:property name="queueCapacity" value="25" />
</beans:bean>
<channel id="ValidatorChannel"/>
<channel id="outBoundjmsChannel"/>
<channel id="outBoundErrorChannel"/>
<channel id="finalOutputChannel"></channel>
<channel id="aggregatorChannel"/>
<jms:inbound-channel-adapter connection-factory="AMQConnectionFactory"
destination="AMQueue" channel="inbound" auto-startup="true"
extract-payload="false" acknowledge="transacted"></jms:inbound-channel-adapter>
<service-activator ref="InBoundProcessor" input-channel="inbound" output-channel="splitterInChannel"></service-activator>
<!-- splitter -->
<splitter ref="Splitter" method="splitInput" input-channel="splitterInChannel" output-channel="splitterOutChannel"/>
<!-- validator -->
<service-activator ref="Validator" method="validate" input-channel="splitterOutChannel" output-channel="ValidatorChannel"/>
<!-- need to add enricher -->
<service-activator ref="Enricher" method="enrich" input-channel="ValidatorChannel" output-channel="outBoundjmsChannel"/>
<!-- outbound gateway -->
<jms:outbound-channel-adapter channel="outBoundjmsChannel" connection-factory="AMQConnectionFactory" destination-name="outputQueue"
message-converter="customMessageConvertor" order="1" >
<jms:request-handler-advice-chain>
<beans:bean class="org.springframework.integration.handler.advice.RequestHandlerRetryAdvice">
<beans:property name="retryTemplate" >
<beans:bean id="retryTemplate" class="org.springframework.retry.support.RetryTemplate">
<beans:property name="retryPolicy">
<beans:bean class="org.springframework.retry.policy.SimpleRetryPolicy">
<beans:property name="maxAttempts" value="2" />
</beans:bean>
</beans:property>
<beans:property name="backOffPolicy">
<beans:bean class="org.springframework.retry.backoff.FixedBackOffPolicy">
<beans:property name="backOffPeriod" value="1000" />
</beans:bean>
</beans:property>
</beans:bean>
</beans:property>
<beans:property name="recoveryCallback">
<beans:bean class="org.springframework.integration.handler.advice.ErrorMessageSendingRecoverer">
<beans:constructor-arg ref="outBoundErrorChannel" />
</beans:bean>
</beans:property>
</beans:bean>
</jms:request-handler-advice-chain>
</jms:outbound-channel-adapter>
<!-- outBound error processor -->
<service-activator ref="ErrorProcessor" method="errorHandling" input-channel="outBoundErrorChannel" output-channel="aggregatorChannel" />
<!-- Post send processor -->
<service-activator ref="PostProcessor" method="Postprocessing" input-channel="outBoundjmsChannel" output-channel="aggregatorChannel" order="2"/>
<!-- aggregator -->
<aggregator ref="Aggregator" correlation-strategy-method="aggregateStrategy" input-channel="aggregatorChannel" output-channel="finalOutputChannel"
release-strategy-method="isRelease" method="aggregate" expire-groups-upon-completion="true"/>
<!-- final processor or responder -->
<service-activator ref="FinalProcessor" method="endProcessing" input-channel="finalOutputChannel"/>
</beans:beans>
In the above configuration as of now i've given the release strategy as false and correlation method as empty string if this works, i will generate UUID for the batch and will attach the UUID in splitter to corrlate.
when debugging the above configuration i noticed the outbound error channel receive whenever it attempts to send to the outbound adapter(in my case its send twice ). I don't want to make an reattempt in one of the application and in another application it needs to attempt for reposting the message.
In both case i want to send the message to outbound error channel after the final attempt to aggregate, if fails i will update the status in ErrorProcessor as failed to send.
Two issues.
1. am receiving duplicate message to the channel and difficult to identify the last failure or success.
2.Couldn't make logic for release strategy and difficult to identify which is the duplicate and whether its successful or not.
In the above case i couldn't find a generic way to compare objects because equals method doesn't have proper attributes to compare and it will not be
correct way to compare with boolean field.
please help me out to resolve this issue to proceed my workflow design and completion.
Much appreciated for guiding me to proceed.
Thanks,
Krish S
currently
public Object errorHandling(Object object){
OutBoundMessage outBoundMessage = null;
if(object instanceof MessagingException){
outBoundMessage =((MessagingException) object).getFailedMessage();
}else{
//TODO: log the message
}
return outBoundMessage;
}
public String aggregateStrategy(OutBoundMessage outBoundMessage){
//TODO: get the UUID from outbound message and return
return "";
}
public List<OutBoundMessage> splitter(InBoundMessage inBoundMessage){
String[] message = inBoundMessage.getRawMessage().split(",");
long uuid = java.util.UUID.randomUUID().getLeastSignificantBits();
List<OutBoundMessage> outBoundMessagelist = new ArrayList<OutBoundMessage>();
for (String string : message) {
OutBoundMessage outBoundMessage = new outBoundMessage();
outBoundMessage.setCorrelationID(uuid);
outBoundMessagelist.add(outBoundMessage);
}
}
Added as default false in the following method to validate
public boolean isRelease(List<OutBoundMessage> outBoundMessage){
//TODO: need to define condition for closing the list aggregation
return false;
}
Please, share your ErrorProcessor source code. And correlation-strategy-method="aggregateStrategy" as well.
I would like to know how you deal with ErrorMessage there and how you restore correlationKey from the message after your ErrorProcessor.
Not sure how you build your own correlationKey, but the <splitter> provide applySequence = true by default. So, the Correlation Details are available in each splitted message to be able to aggregate afterwards.
For your ErrorMessage from the ErrorMessageSendingRecoverer I can recommend to pay attention to the Exception payload there. It looks like (from the ErrorMessageSendingRecoverer source code):
else if (!(lastThrowable instanceof MessagingException)) {
lastThrowable = new MessagingException((Message<?>) context.getAttribute("message"),
lastThrowable.getMessage(), lastThrowable);
}
....
messagingTemplate.send(new ErrorMessage(lastThrowable));
So, that MessagingException, has a "guilty" message for the Exception and exactly that message has an appropriate Correlation Details headers for aggregator. Therefore you should rely on them if you'd like to aggregate errors to the same message group.
Finally I understood how it works,
I've a boolean set to true in message convertor and in Errorhandle I set it to false and return null so the recovery is that message is received as failed message to aggregator and understood what happens when I return the object
Thanks #ArtemBilan, your code block gave me an insight of what's happening and what should I do
I'm continuing to study SI and in the same time i'm trying to build an application.
My application flow is this:
Read XML file and split each tag
Each tag have define an attribute called "interval", and i need to create a job that will be repeated, according to this value.
When the job execution is terminated, need to invoke a Web Service to store information
If WBS invokation fails, try to send info by email
Right now i'm arrived on point one ( :D ) of this flow, now i'm trying to move forward and first check the error handling (point 4 of the flow).
This is the actual configuration that i have and this works fine splitting the tag and then invoking the right service-activator:
<context:component-scan base-package="it.mypkg" />
<si:poller id="poller" default="true" fixed-delay="1000"/>
<si:channel id="rootChannel" />
<si-xml:xpath-splitter id="mySplitter" input-channel="rootChannel" output-channel="routerChannel" create-documents="true">
<si-xml:xpath-expression expression="//service" />
</si-xml:xpath-splitter>
<si-xml:xpath-router id="router" input-channel="routerChannel" evaluate-as-string="true">
<si-xml:xpath-expression expression="concat(name(./node()), 'Channel')" />
</si-xml:xpath-router>
<si:service-activator input-channel="serviceChannel" output-channel="endChannel">
<bean class="it.mypkg.Service" />
</si:service-activator>
The endChannel will need to receive all messages from the several channel (sent by the router) and then invoke the WBS. Right now i'm jkust creating classes to check if the flow will works or not.
The remaining part of my applicationContext.xml is this:
<!-- Create a poller that will be used by endChannel -->
<si:poller id="poller" default="true" fixed-delay="1000" error-channel="failedInvocationChannel" />
<!--- take messages from serviceChannel and redirect to endChannel, that is responsable to receive messages from all channels created by the router -->
<si:service-activator input-channel="serviceChannel" output-channel="endChannel">
<bean class="it.mypkg.Service" />
</si:service-activator>
<!-- end channel is a queue -->
<si:channel id="endChannel">
<si:queue capacity="10"/>
</si:channel>
<!-- Messages are taken from the queue.. -->
<si:service-activator input-channel="endChannel">
<bean class="it.mypkg.Invokator" />
</si:service-activator>
<!-- Service activator that handle the errors on the queue -->
<si:channel id="failedInvocationChannel" />
<si:service-activator input-channel="failedInvocationChannel">
<bean class="it.mypkg.Resubmitter" />
</si:service-activator>
but when i run my application i got this error:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.integration.handler.MessageHandlerChain#0': Cannot create inner bean 'org.springframework.integration.handler.MessageHandlerChain#0$child#1.handler' of type [org.springframework.integration.config.ServiceActivatorFactoryBean] while setting bean property 'handlers' with key [1]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.integration.handler.MessageHandlerChain#0$child#1.handler': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalArgumentException: Target object of type [class org.springframework.integration.channel.QueueChannel] has no eligible methods for handling Messages.
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:313)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:122)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveManagedList(BeanDefinitionValueResolver.java:382)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:157)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1481)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1226)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:838)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:537)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:197)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:172)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:158)
I've read a lot and i'm a little bit confused about all the components that can be used... maybe my error is because i'm trying to use components in the wrong way...
EDIT: Configuration updated with error-channel on poller and removed chain to handle the error
<si:service-activator ref="endChannel" method="dispatch" />
You can't use a ref to a channel in a service activator.
Also, it's better to give elements like chains an id so exceptions are easier to debug.
Also, you generally shouldn't be manipulating the errorChannel header; it's better to add an error-channel to the poller and route the error flow that way.