Kafka outbound channel can't take message from a channel - spring

There is a channel :
<integration:channel id="sampleChannel">
</integration:channel>
And there is a kafka outbound channel with sampleChannel value for channel property :
<int-kafka:outbound-channel-adapter id="kafkaOutboundChannelAdapter"
kafka-template="template"
auto-startup="false"
channel="sampleChannel"
topic="foo"
sync="false"
send-failure-channel="errorChannel"
partition-id-expression="1">
</int-kafka:outbound-channel-adapter>
When message sends and get to sampleChannel, this exception throws :
org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel 'org.springframework.context.support.ClassPathXmlApplicationContext#1623b78d.sampleChannel'
Why kafka outbound can't take message from the sampleChannel ?

Your auto-startup is set to false, so at the time when Application Context is started there is no subscriber to the sampleChannel.
Set auto-startup to true. Or change your sampleChannel to be pollable of publish-subscribe channel.

Related

Shutting down JMS listener container waiting for shutdown of message listener invokers

Post invoking shutdown on JMS listener container it is waiting for Message listener invokers to be shutdown.
We are calling this shut down in Job event listener post completion of the job, and there are no messages to be consumed from request queue, so not sure why these message listeners are not shutting down. below are logs from Server post shutdown call.
INFO [org.springframework.batch.core.launch.support.SimpleJobLauncher] (aspAsyncExecutor-1) Job: [FlowJob: [name=SENEXTRACT]] completed with the following parameters: [{​​​​​​​--listId=15195, --letterId=BF2025, --randomId=99a3d764-8cbf-4dbd-81c8-a5442e6e67e5}​​​​​​​] and the following status: [COMPLETED] in 4m20s353ms
DEBUG [org.springframework.integration.channel.DirectChannel] (aspAsyncExecutor-1) preSend on channel 'bean 'controlChannel'', message: GenericMessage [payload=#senExtractInGateway.stop(), headers={​​​​​​​id=6d7cdaaa-21e5-9a2f-e2ab-d83523747837, timestamp=1620803972934}​​​​​​​]
DEBUG [org.springframework.integration.handler.ServiceActivatingHandler] (aspAsyncExecutor-1) ServiceActivator for [org.springframework.integration.handler.ExpressionCommandMessageProcessor#2decec67] (org.springframework.integration.config.ExpressionControlBusFactoryBean#0) received message: GenericMessage [payload=#senExtractInGateway.stop(), headers={​​​​​​​id=6d7cdaaa-21e5-9a2f-e2ab-d83523747837, timestamp=1620803972934}​​​​​​​]
DEBUG [org.springframework.jms.listener.DefaultMessageListenerContainer] (aspAsyncExecutor-1) Shutting down JMS listener container
DEBUG [org.springframework.jms.listener.DefaultMessageListenerContainer] (aspAsyncExecutor-1) Waiting for shutdown of message listener invokers
DEBUG [org.springframework.jms.listener.DefaultMessageListenerContainer] (aspAsyncExecutor-1) Still waiting for shutdown of 30 message listener invokers (iteration 0)
Configuration is as follows.
<int-jms:inbound-gateway
id="senExtractInGateway" connection-factory="connectionFactory"
correlation-key="JMSCorrelationID"
request-channel="senExtractProcessingRequestChannel"
request-destination-name="senExtractRequestQueue"
reply-channel="senExtractProcessingReplyChannel"
default-reply-queue-name="senExtractReplyQueue"
concurrent-consumers="1" max-concurrent-consumers="30"
max-messages-per-task="1" reply-timeout="1800000"
receive-timeout="1800000" auto-startup="false"/>
<integration:channel id="controlChannel" />
<integration:control-bus input-channel="controlChannel" />
Code Snippet:
MessageChannel controlChannel = appContext.getBean("controlChannel", MessageChannel.class);
controlChannel.send(new GenericMessage<String>("#senExtractInGateway.start()"));
logger.info("Received before adapter started: ");
//controlChannel.send(new GenericMessage<String>("#senExtractSrvActivator.start()"));
JobExecution execution = jobLauncher.run(job, jobParameters);
controlChannel.send(new GenericMessage<String>("#senExtractInGateway.stop()"));
Server Threads
You have this config receive-timeout="1800000". So, it is not a surprise that your consumer is blocked for those 30 mins. See its JavaDocs:
/**
* Actually receive a message from the given consumer.
* #param consumer the JMS MessageConsumer to receive with
* #param timeout the receive timeout (a negative value indicates
* a no-wait receive; 0 indicates an indefinite wait attempt)
* #return the JMS Message received, or {#code null} if none
* #throws JMSException if thrown by JMS API methods
* #since 4.3
* #see #RECEIVE_TIMEOUT_NO_WAIT
* #see #RECEIVE_TIMEOUT_INDEFINITE_WAIT
*/
#Nullable
protected Message receiveFromConsumer(MessageConsumer consumer, long timeout) throws JMSException {
As long as consumers are blocked waiting for a message in the destination, the container cannot claim its state as stopped, therefor it waits for those consumers to become free and release resources.

Artemis: How to stop consuming messages on error?

How to configure ActiveMQ Artemis or my Spring JMS client to not consume any other message on error?
I've configured my broker as follows:
<addresses>
<address name="SimplePointToPoint">
<anycast>
<queue name="SimplePointToPoint"/>
</anycast>
</address>
</addresses>
<address-settings>
<address-setting match="SimplePointToPoint">
<max-delivery-attempts>-1</max-delivery-attempts>
</address-setting>
</address-settings>
This is the code of my consumer:
#JmsListener(destination = "SimplePointToPoint")
public void consumeMessage(Message<String> message) {
if (message.getPayload().contains("error"))
throw new RuntimeException();
log.info("received message: {}", message.getPayload());
}
When sending message1, message2 with error and message3 I want the consumer to process message1 and retry message2 with error forever. message3 should not be processed until message2 with error is successfully consumed. What actually happens is that message3 gets consumed between retries. How to change this behavior? Any ideas?
ActiveMQ prefetch is 1000 by default.
See the documentation.
You can specify an instance of the ActiveMQPrefetchPolicy on an ActiveMQConnectionFactory or ActiveMQConnection. This allows you to configure all the individual prefetch values; as each different quality of service has a different value. e.g.
persistent queues (default value: 1000)
...

Spring Integration. Gateway reply error on outbound exception

I have the next configuration:
Inbound
<int:gateway id="inGateway" service-interface="XXX"
error-channel="errorChannel"
default-request-channel="requestChannel"
default-reply-channel="replyChannel" />
Outbound:
<ws:outbound-gateway id="ws-outbound-gateway"
request-channel="inbound" reply-channel="outbound" uri="XXX" />
Chain 1:
<int:chain input-channel="requestChannel" output-channel="inbound">
XXX </int:chain>
Chain 2:
<int:chain input-channel="outbound" output-channel="replyChannel"> XXX
</int:chain>
Error:
<int:chain input-channel="errorChannel" output-channel="replyChannel">
<int:transformer ref="logicTransformers" method="errorTransformerMethod"></int:transformer>
</int:chain>
</beans>
Java Transformer:
final GenericError errorCatalog = errorCatalog(errorMessage);
LOGGER.warn("Transformed error from catalog: {}", errorCatalog);
final MessageBuilder<Document> builder =
MessageBuilder.withPayload(XmlUtil.parseToDocument(errorCatalog)).copyHeaders(errorMessage.getHeaders()).copyHeadersIfAbsent(errorMessage.getHeaders());
When the webservice of outbound is down the error go into errorChannel transformer but to reponse we have the next error:
o.s.m.c.GenericMessagingTemplate$TemporaryReplyChannel#242 Reply
message received but the receiving thread has exited due to an
exception while sending the request message:GenericMessage
[payload=[#document: null], headers={spanTraceId=8bf90ea9ff4266c8,
spanId=598680bae5f913d5, spanParentSpanId=8bf90ea9ff4266c8,
replyChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel#76c751de,
functionalId=PRUEBASOA12,
errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel#76c751de,
messageSent=true, id=2108386f-99db-98b9-3d30-3bcf45335424,
spanSampled=1, spanName=message:requestChannel}]
We don't understand... because we have the same flow with
In case of error on the service level the original message is wrapped to the MessagingException and the ErrorMessage with that payload is sent to the errorChannel. Even if you use replyChannel explicitly, you still have to ensure the replyChannel header, which is populated by the inbound gateway. And exactly this header plays the main role in the request-reply behavior in that gateway.
That replyHeader is still present in your error flow, but it is already a part of the failedMessage in the MessagingException payload.
So, your logicTransformers.errorTransformerMethod should extract that replyChannel header for the real reply from this method to be sent to the explicit replyChannel. Or you can omit this replyChannel at all because any way the real sendAndReceive is based on the replyChannel header.
Please, read more info in the Reference Manual:
https://docs.spring.io/spring-integration/docs/4.3.11.RELEASE/reference/html/messaging-endpoints-chapter.html#gateway
https://docs.spring.io/spring-integration/docs/4.3.11.RELEASE/reference/html/configuration.html#namespace-errorhandler

Publisher should wait till broker is available

I have a simple publisher, which sends messages to a queue.
<int:channel id="publishChannel"/>
<int-jms:outbound-channel-adapter channel="publishChannel" destination="testQueue" session-transacted="true"/>
#Publisher(channel = "publishChannel")
public String sendMessage (String text) {
return text;
}
If the broker crashes, the publisher throws an MessageHandlingException.
Is it possible to block the publisher, till the broker is available again or to make a periodic retry?
You can add a retry advice to the outbound adapter.
<int-jms:outbound-channel-adapter channel="publishChannel" destination="testQueue" session-transacted="true>
<int:request-handler-advice-chain>
<ref bean="myRetryAdvice" />
</request-handler-advice-chain>
</int-jms:outbound-channel-adapter>
You can configure the advice with a backoff policy (e.g. exponential) and to take some action when retries are exhausted (rather than throwing the final exception).

'Write-Only' over a TCP connection with Spring Integration

I am using int-ip:tcp-connection-factory and int-ip:tcp-outbound-gateway to communicate with an external server. The protocol for most of the services offered by the server follows the standard request-response style... which is working great. However, there are a few situations where I only need to send a request and no response is expected.
My question is, how do I configure my channels and connections so that I can specify whether or not to wait for a response? Currently I can't find a way and Spring always blocks after sending the request even if I am not expecting a response.
EDIT:
As suggested, I have used a tcp-outbound-channel-adapter. My config file has only the followings:
<int:channel id="requestChannel" />
<int-ip:tcp-outbound-channel-adapter
channel="requestChannel" connection-factory="client" />
<int-ip:tcp-connection-factory id="client"
type="client" host="smtp.gmail.com" port="587" single-use="false"
so-timeout="10000" />
And here's my Main class:
public final class Main {
private static final Logger LOGGER = Logger.getLogger(Main.class);
public static void main(final String... args) throws IOException {
LOGGER.debug("entered main()...");
final AbstractApplicationContext context = new ClassPathXmlApplicationContext(
"classpath:*-context.xml");
MessageChannel requestChannel = context.getBean("requestChannel", MessageChannel.class);
requestChannel.send(MessageBuilder.withPayload("QUIT").build());
LOGGER.debug("exiting main()...");
}
}
Finally this is what I get in my log:
11:57:15.877 INFO [main][com.together.email.Main] entered main()...
11:57:16.295 INFO [main][org.springframework.integration.config.xml.DefaultConfiguringBeanFactoryPostProcessor] No bean named 'errorChannel' has been explicitly defined. Therefore, a default PublishSubscribeChannel will be created.
11:57:16.295 INFO [main][org.springframework.integration.config.xml.DefaultConfiguringBeanFactoryPostProcessor] No bean named 'taskScheduler' has been explicitly defined. Therefore, a default ThreadPoolTaskScheduler will be created.
11:57:16.480 INFO [main][org.springframework.integration.ip.tcp.connection.TcpNetClientConnectionFactory] started client
11:57:16.480 INFO [main][org.springframework.integration.endpoint.EventDrivenConsumer] Adding {ip:tcp-outbound-channel-adapter} as a subscriber to the 'requestChannel' channel
11:57:16.480 INFO [main][org.springframework.integration.channel.DirectChannel] Channel 'requestChannel' has 1 subscriber(s).
11:57:16.480 INFO [main][org.springframework.integration.endpoint.EventDrivenConsumer] started org.springframework.integration.config.ConsumerEndpointFactoryBean#0
11:57:16.480 INFO [main][org.springframework.integration.endpoint.EventDrivenConsumer] Adding {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel
11:57:16.481 INFO [main][org.springframework.integration.channel.PublishSubscribeChannel] Channel 'errorChannel' has 1 subscriber(s).
11:57:16.481 INFO [main][org.springframework.integration.endpoint.EventDrivenConsumer] started _org.springframework.integration.errorLogger
11:57:16.509 DEBUG [main][org.springframework.integration.channel.DirectChannel] preSend on channel 'requestChannel', message: [Payload=QUIT][Headers={timestamp=1381021036509, id=860ebe82-06c6-4393-95c7-0ece1a0a0e5d}]
11:57:16.509 DEBUG [main][org.springframework.integration.ip.tcp.TcpSendingMessageHandler] org.springframework.integration.ip.tcp.TcpSendingMessageHandler#0 received message: [Payload=QUIT][Headers={timestamp=1381021036509, id=860ebe82-06c6-4393-95c7-0ece1a0a0e5d}]
11:57:16.509 DEBUG [main][org.springframework.integration.ip.tcp.connection.TcpNetClientConnectionFactory] Opening new socket connection to smtp.gmail.com:587
11:57:16.745 DEBUG [main][org.springframework.integration.ip.tcp.connection.TcpNetConnection] New connection smtp.gmail.com:587:550c9b68-10a0-442d-b65d-d25d28df306b
11:57:16.748 DEBUG [main][org.springframework.integration.ip.tcp.TcpSendingMessageHandler] Got Connection smtp.gmail.com:587:550c9b68-10a0-442d-b65d-d25d28df306b
11:57:16.749 DEBUG [pool-1-thread-1][org.springframework.integration.ip.tcp.connection.TcpNetConnection] TcpListener exiting - no listener and not single use
11:57:16.750 DEBUG [main][org.springframework.integration.ip.tcp.connection.TcpNetConnection] Message sent [Payload=QUIT][Headers={timestamp=1381021036509, id=860ebe82-06c6-4393-95c7-0ece1a0a0e5d}]
11:57:16.750 DEBUG [main][org.springframework.integration.channel.DirectChannel] postSend (sent=true) on channel 'requestChannel', message: [Payload=QUIT][Headers={timestamp=1381021036509, id=860ebe82-06c6-4393-95c7-0ece1a0a0e5d}]
11:57:16.751 INFO [main][com.together.email.Main] exiting main()...
I have set Spring's logging to debug level so that I can give you more details. As you can see from the last line of the log, my main exits. However, unfortunately the application doesn't terminate as [pool-1-thread-1] continues running. This thread comes to life as soon as send is invoked on requestChannel. Any idea what's going on here?
[In this example, I am sending an SMTP QUIT message as soon as the application connects to Google. In practice, I would actually not start with a QUIT. For example, at the beginning I may start with a HELO message. I have tried hooking in a tcp-inbound-channel-adapter to get the message response and that works great. The problem is with messages where I don't expect a reply.]
So, I suggest you to inject into the <int-ip:tcp-connection-factory> some 'fake' task-executor:
public class NullExecutor implements Executor {
public void execute(Runnable command) {}
}
In this case your connection from AbstractClientConnectionFactory#obtainConnection() won't be configured (runned) to read from socket.
However System.exit(0); as last line of your main is enough. In this case all thread will be terminated, if they aren't daemons.

Resources