Java Websocket client running on linux VM not able to receive response from Websocket server - spring-boot

I have a Java websocket client and server developed with spring-boot. Websocket server deployed in pod .
When i try connecting my wss server from my eclipse console and windows terminal i am able to receive message from server but on the other hand no server response received when i run the client from a linux vm
I am really stuck. Any help will be appreciated.
**Java Client Code:**
public void connectPlain() throws InterruptedException, ExecutionException, IOException {
WebSocketHttpHeaders header = new WebSocketHttpHeaders();
header.set("IDS-SESSION-ID", sessionId);
this.session = new StandardWebSocketClient().doHandshake(new TextWebSocketHandler() {
#Override
public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
log.info("Server Session {} " , session.getId());
session.setTextMessageSizeLimit(100 * 1024 * 1024);
log.info("Ack from Server:: {} " ,message.getPayload());
}
#Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
log.info("Client Session {} " , session.getId());
}
#Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
}
}, header, URI.create(url)).get();
if(this.session.isOpen()) {
while(true) {
log.info("Session Open ****");
session.sendMessage(new TextMessage("Client-"));
Thread.sleep(10000);
}
}
}
**Websocket Server Code**
public class SocketHandler extends TextWebSocketHandler {
ConcurrentWebSocketSessionDecorator cws;
#Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
session.setTextMessageSizeLimit(100 * 1024 * 1024);
log.info("Connected... with messageBufferSize :: {},{} ", session.getId(), session.getTextMessageSizeLimit());
cws = new
ConcurrentWebSocketSessionDecorator(session,3000,100*1024*1024);
}
#Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String tenantId = session.getHandshakeHeaders().getFirst("tenantid");
log.info(message.getPayload());
session.sendMessage(new TextMessage("Ack From server"));
}
Exception:
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:108)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65)
Caused by: java.io.IOException: java.util.concurrent.TimeoutException
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendMessageBlock(WsRemoteEndpointImplBase.java:327)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendMessageBlock(WsRemoteEndpointImplBase.java:254)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendPartialString(WsRemoteEndpointImplBase.java:227)
at org.apache.tomcat.websocket.WsRemoteEndpointBasic.sendText(WsRemoteEndpointBasic.java:49)
at org.springframework.web.socket.adapter.standard.StandardWebSocketSession.sendTextMessage(StandardWebSocketSession.java:215)
at org.springframework.web.socket.adapter.AbstractWebSocketSession.sendMessage(AbstractWebSocketSession.java:106)
at com.informatica.poc.batch.ConnectorClient.connectPlain(ConnectorClient.java:186)
at com.informatica.poc.batch.BatchApplication.main(BatchApplication.java:48)
... 8 more
Caused by: java.util.concurrent.TimeoutException
at org.apache.tomcat.websocket.AsyncChannelWrapperSecure$WrapperFuture.get(AsyncChannelWrapperSecure.java:515)
at org.apache.tomcat.websocket.AsyncChannelWrapperSecure$LongToIntegerFuture.get(AsyncChannelWrapperSecure.java:561)
at org.apache.tomcat.websocket.AsyncChannelWrapperSecure$LongToIntegerFuture.get(AsyncChannelWrapperSecure.java:524)
at org.apache.tomcat.websocket.WsRemoteEndpointImplClient.doWrite(WsRemoteEndpointImplClient.java:62)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase$OutputBufferSendHandler.write(WsRemoteEndpointImplBase.java:952)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.writeMessagePart(WsRemoteEndpointImplBase.java:509)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendMessageBlock(WsRemoteEndpointImplBase.java:314)
... 15 more

Related

Cannot connect to rabbitmq STOMP from Spring boot

I have used the RabbitMQ docker image which has STOMP enabled. With the following configuration, when I try to run my Spring Boot Application, I am getting an exception.
StackTrace:
2020-11-21 16:03:07.620 INFO 28504 --- [ient-loop-nio-1] o.s.m.s.s.StompBrokerRelayMessageHandler : TCP connection failure in session system: Failed to connect: Connection refused: /127.0.0.1:61613
io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: /127.0.0.1:61613
Caused by: java.net.ConnectException: Connection refused
at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method) ~[na:1.8.0_242]
at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:714) ~[na:1.8.0_242]
at io.netty.channel.socket.nio.NioSocketChannel.doFinishConnect(NioSocketChannel.java:330) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final]
at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:334) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:702) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989) ~[netty-common-4.1.51.Final.jar:4.1.51.Final]
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.51.Final.jar:4.1.51.Final]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.51.Final.jar:4.1.51.Final]
at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_242]
Dockerfile
FROM rabbitmq:3-management
RUN rabbitmq-plugins enable --offline rabbitmq_stomp
EXPOSE 61613
The logs from Rabbitmq container looks fine to me.
WebSocketConfig.java looks like:
#EnableWebSocketMessageBroker
#Configuration
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws-connection")
.setAllowedOrigins("*")
.withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableStompBrokerRelay("/topic", "/queue")
.setRelayPort(61613)
.setRelayHost("127.0.0.1")
.setClientPasscode("guest")
.setClientLogin("guest");
registry.setApplicationDestinationPrefixes("/ws");
}
}
pom.xml
<dependency>
<groupId>io.projectreactor.netty</groupId>
<artifactId>reactor-netty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
What's wrong with the configuration? Can anyone help me?
I think you made a mistake while exposing the rabbitmq stomp port 61613 for the client. By the way, I tested with a similar configuration it works for me.
For implementation please check my demo application on GitHub or read the following details.
Dockerfile
FROM rabbitmq:3-management
RUN rabbitmq-plugins enable --offline rabbitmq_stomp
EXPOSE 15671 15672 61613
Server Implementation
Message Contract
public class ZbytesMessage {
private String from;
private String text;
...getters and setters...
}
WebSocket Configuration
#Configuration
#EnableWebSocketMessageBroker
public class StompConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/zsockets")
.setAllowedOrigins("*").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableStompBrokerRelay("/topic", "/queue")
.setRelayHost("localhost")
.setRelayPort(61613)
.setClientLogin("guest")
.setClientPasscode("guest");
config.setApplicationDestinationPrefixes("/zbytes");
}
}
Web Controller
#Controller
public class ZbytesController {
private static final Logger LOG = LoggerFactory.getLogger(ZbytesController.class);
#MessageMapping("/hello")
#SendTo("/topic/greetings")
public ZbytesMessage greeting(ZbytesMessage msg) throws Exception {
Thread.sleep(1000); // simulated delay
LOG.info("Received : {} from: {} ", msg.getText(), msg.getFrom());
return msg;
}
}
Server Runner
#SpringBootApplication
public class ServerRunner {
public static void main(String[] args) {
SpringApplication.run(ServerRunner.class, args);
}
}
Client Implementation
public class HelloClient {
private static final WebSocketHttpHeaders headers = new WebSocketHttpHeaders();
private static final Logger LOG = LoggerFactory.getLogger(HelloClient.class);
public static void main(String[] args) throws Exception {
HelloClient helloClient = new HelloClient();
ListenableFuture<StompSession> f = helloClient.connect();
StompSession stompSession = f.get();
LOG.info("Subscribing to greeting topic using session {}", stompSession);
helloClient.subscribeGreetings(stompSession);
LOG.info("Sending hello message {}", stompSession);
helloClient.sendHello(stompSession);
Thread.sleep(60000);
}
public ListenableFuture<StompSession> connect() {
Transport webSocketTransport = new WebSocketTransport(new StandardWebSocketClient());
List<Transport> transports = Collections.singletonList(webSocketTransport);
SockJsClient sockJsClient = new SockJsClient(transports);
sockJsClient.setMessageCodec(new Jackson2SockJsMessageCodec());
WebSocketStompClient stompClient = new WebSocketStompClient(sockJsClient);
String url = "ws://{host}:{port}/zsockets";
return stompClient.connect(url, headers, new MyHandler(), "localhost", 8080);
}
public void subscribeGreetings(StompSession stompSession) {
stompSession.subscribe("/topic/greetings", new StompFrameHandler() {
public Type getPayloadType(StompHeaders stompHeaders) {
return byte[].class;
}
public void handleFrame(StompHeaders stompHeaders, Object o) {
LOG.info("Received greeting {}", new String((byte[]) o));
}
});
}
public void sendHello(StompSession stompSession) {
String jsonHello = "{ \"from\" : \"suraj\", \"text\" : \"Hi zbytes!\" }";
stompSession.send("/zbytes/hello", jsonHello.getBytes());
}
private static class MyHandler extends StompSessionHandlerAdapter {
#Override
public void afterConnected(StompSession stompSession, StompHeaders stompHeaders) {
LOG.info("Now connected");
}
}
}
To Run
Build the docker image and run it (don't forget to expose port 61613). (Note: I would prefer docker-compose.yaml)
docker build -t zbytes/rabbitmq .
docker run -p61613:61613 zbytes/rabbitmq
Run ServerRunner java main class.
Run HelloClient java main class.
Server Output
i.g.zbytes.demo.server.ZbytesController : Received : Hi zbytes! from: suraj
Client Output
Received greeting {"from":"suraj","text":"Hi zbytes!"}

SpringBoot + Rabbitmq - DLQ queue not working

I have setup dlq and dlx, but failed message is not redirecting to dlq.
I am trying to send message from java app as well as from rabbitmq server to MESSAGES.EXCHANGE, in both case i am getting message but after throwing the exception message should redirect to DLX.MESSAGES.EXCHANGE but it is happening.
Below is java code and screen shot of rabbitmq serer. everything looks right to me. could not find any problem in code or in rabbitmq server.
Queue setup code -
public class DLQAmqpConfiguration {
public static final String DLX_MESSAGES_EXCHANGE = "DLX.MESSAGES.EXCHANGE";
public static final String DLQ_MESSAGES_QUEUE = "DLQ.MESSAGES.QUEUE";
public static final String MESSAGES_QUEUE = "MESSAGES.QUEUE";
public static final String MESSAGES_EXCHANGE = "MESSAGES.EXCHANGE";
public static final String ROUTING_KEY_MESSAGES_QUEUE = "ROUTING_KEY_MESSAGES_QUEUE";
#Bean
Queue messagesQueue() {
return QueueBuilder.durable(MESSAGES_QUEUE)
.withArgument("x-dead-letter-exchange", DLX_MESSAGES_EXCHANGE)
.build();
}
#Bean
DirectExchange messagesExchange() {
return new DirectExchange(MESSAGES_EXCHANGE);
}
#Bean
Binding bindingMessages() {
return BindingBuilder.bind(messagesQueue()).to(messagesExchange()).with(ROUTING_KEY_MESSAGES_QUEUE);
}
#Bean
FanoutExchange deadLetterExchange() {
return new FanoutExchange(DLX_MESSAGES_EXCHANGE);
}
#Bean
Queue deadLetterQueue() {
return QueueBuilder.durable(DLQ_MESSAGES_QUEUE).build();
}
#Bean
Binding deadLetterBinding() {
return BindingBuilder.bind(deadLetterQueue()).to(deadLetterExchange());
}
}
Producer -
this.template.convertAndSend(DLQAmqpConfiguration.MESSAGES_EXCHANGE,
DLQAmqpConfiguration.ROUTING_KEY_MESSAGES_QUEUE, message);
Cunsumer -
#RabbitListener(queues = DLQAmqpConfiguration.MESSAGES_QUEUE)
public void receiveMessage(Message message) throws BusinessException {
System.out.println("Received failed message, re-queueing: " + message.toString());
System.out.println("Received failed message, re-queueing: " + message.getMessageProperties().getReceivedRoutingKey());
throw new BusinessException();
}
// this code never running
#RabbitListener(queues = DLQAmqpConfiguration.DLQ_MESSAGES_QUEUE)
public void processFailedMessages(Message message) {
System.out.println("Received failed message: " + message.toString());
}
Exchange -
QUEUE -
Logs -
Received failed message, re-queueing: (Body:'[B#55c36bc9(byte[26])' MessageProperties [headers={}, contentLength=0, receivedDeliveryMode=PERSISTENT, redelivered=true, receivedExchange=MESSAGES.EXCHANGE, receivedRoutingKey=ROUTING_KEY_MESSAGES_QUEUE, deliveryTag=5444, consumerTag=amq.ctag-KrxkDPlc_uoqHOx_bbnvnA, consumerQueue=MESSAGES.QUEUE])
Received failed message, re-queueing: ROUTING_KEY_MESSAGES_QUEUE
2020-08-27 21:36:33.460 WARN 13192 --- [ntContainer#0-1] s.a.r.l.ConditionalRejectingErrorHandler : Execution of Rabbit message listener failed.
org.springframework.amqp.rabbit.support.ListenerExecutionFailedException: Listener method 'public void com.example.rabbitmq.RabbitmqApplication.receiveMessage(org.springframework.amqp.core.Message) throws com.example.rabbitmq.errorhandler.BusinessException' threw exception
at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:228) ~[spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.invokeHandlerAndProcessResult(MessagingMessageListenerAdapter.java:148) ~[spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.java:133) ~[spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1591) ~[spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.actualInvokeListener(AbstractMessageListenerContainer.java:1510) ~[spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:1498) ~[spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:1489) ~[spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:1433) ~[spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:970) [spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:916) [spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1600(SimpleMessageListenerContainer.java:83) [spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.mainLoop(SimpleMessageListenerContainer.java:1291) [spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1197) [spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_131]
Caused by: com.example.rabbitmq.errorhandler.BusinessException: null
You have to set spring.rabbitmq.listener.simple.default-requeue-rejected=false (or ...direct... if using the direct container instead of the simple container) or throw AmqpRejectAndDontRequeueException.
Otherwise, the failed message will be requeued and redelivered.
#SpringBootApplication
public class So63620066Application {
public static void main(String[] args) {
SpringApplication.run(So63620066Application.class, args);
}
public static final String DLX_MESSAGES_EXCHANGE = "DLX.MESSAGES.EXCHANGE";
public static final String DLQ_MESSAGES_QUEUE = "DLQ.MESSAGES.QUEUE";
public static final String MESSAGES_QUEUE = "MESSAGES.QUEUE";
public static final String MESSAGES_EXCHANGE = "MESSAGES.EXCHANGE";
public static final String ROUTING_KEY_MESSAGES_QUEUE = "ROUTING_KEY_MESSAGES_QUEUE";
#Bean
Queue messagesQueue() {
return QueueBuilder.durable(MESSAGES_QUEUE)
.withArgument("x-dead-letter-exchange", DLX_MESSAGES_EXCHANGE)
.build();
}
#Bean
DirectExchange messagesExchange() {
return new DirectExchange(MESSAGES_EXCHANGE);
}
#Bean
Binding bindingMessages() {
return BindingBuilder.bind(messagesQueue()).to(messagesExchange()).with(ROUTING_KEY_MESSAGES_QUEUE);
}
#Bean
FanoutExchange deadLetterExchange() {
return new FanoutExchange(DLX_MESSAGES_EXCHANGE);
}
#Bean
Queue deadLetterQueue() {
return QueueBuilder.durable(DLQ_MESSAGES_QUEUE).build();
}
#Bean
Binding deadLetterBinding() {
return BindingBuilder.bind(deadLetterQueue()).to(deadLetterExchange());
}
#RabbitListener(queues = MESSAGES_QUEUE)
public void receiveMessage(Message message) {
System.out.println("Received failed message, re-queueing: " + message.toString());
System.out.println(
"Received failed message, re-queueing: " + message.getMessageProperties().getReceivedRoutingKey());
throw new RuntimeException("fail");
}
#RabbitListener(queues = DLQ_MESSAGES_QUEUE)
public void processFailedMessages(Message message) {
System.out.println("Received failed message: " + message.toString());
}
#Bean
public ApplicationRunner runner(RabbitTemplate template) {
return args -> {
template.convertAndSend(MESSAGES_EXCHANGE,
ROUTING_KEY_MESSAGES_QUEUE, "foo");
};
}
}
spring.rabbitmq.listener.simple.default-requeue-rejected=false
Received failed message, re-queueing: ROUTING_KEY_MESSAGES_QUEUE
2020-08-27 12:49:41.056 WARN 11489 --- [ntContainer#0-1] s.a.r.l.ConditionalRejectingErrorHandler : Execution of Rabbit message listener failed.
org.springframework.amqp.rabbit.support.ListenerExecutionFailedException: Listener method 'public void com.example.demo.So63620066Application.receiveMessage(org.springframework.amqp.core.Message)' threw exception
at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:228) ~[spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.invokeHandlerAndProcessResult(MessagingMessageListenerAdapter.java:148) ~[spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.java:133) ~[spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1591) ~[spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.actualInvokeListener(AbstractMessageListenerContainer.java:1510) ~[spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:1498) ~[spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:1489) ~[spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:1433) ~[spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:970) [spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:916) [spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1600(SimpleMessageListenerContainer.java:83) [spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.mainLoop(SimpleMessageListenerContainer.java:1291) [spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1197) [spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_212]
Caused by: java.lang.RuntimeException: fail
at com.example.demo.So63620066Application.receiveMessage(So63620066Application.java:71) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_212]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_212]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_212]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_212]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:171) ~[spring-messaging-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:120) ~[spring-messaging-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.amqp.rabbit.listener.adapter.HandlerAdapter.invoke(HandlerAdapter.java:53) ~[spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:220) ~[spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
... 13 common frames omitted
Received failed message: (Body:'foo' MessageProperties [headers={x-first-death-exchange=MESSAGES.EXCHANGE, x-death=[{reason=rejected, count=1, exchange=MESSAGES.EXCHANGE, time=Thu Aug 27 12:49:41 EDT 2020, routing-keys=[ROUTING_KEY_MESSAGES_QUEUE], queue=MESSAGES.QUEUE}], x-first-death-reason=rejected, x-first-death-queue=MESSAGES.QUEUE}, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, redelivered=false, receivedExchange=DLX.MESSAGES.EXCHANGE, receivedRoutingKey=ROUTING_KEY_MESSAGES_QUEUE, deliveryTag=3, consumerTag=amq.ctag--VIXT0V3hhBrlfTFqI5uxg, consumerQueue=DLQ.MESSAGES.QUEUE])

Serialization Exception on using SendToDlqAndContinue spring kafka streams binder

I am trying to send messages to DLQ on processing exception however I keep getting serialization exception when I use SendToDlqAndContinue from Spring-boot-kafka-streams-binder
#EnableBinding(ConsumerStreamsWay.KStreamBinding.class)
public class ConsumerStreamsWay {
#Autowired
private SendToDlqAndContinue dlqHandler;
#StreamListener
public void topic3Processor2(#Input("topic3") KStream<String, String> input) {
input.process(() -> new Processor<String, String>() {
ProcessorContext context;
#Override
public void init(ProcessorContext context) {
this.context = context;
}
#Override
public void process(String key, String value) {
try {
System.out.println("Received from topic3: " + value);
if (value.startsWith("fail")) {
System.out.println("This is supposed to fail.");
throw new RuntimeException("Failing knowingly.");
}
} catch (Exception e) {
//explicitly provide the kafka topic corresponding to the input binding as the first argument.
//DLQ handler will correctly map to the dlq topic from the actual incoming destination.
System.out.println("Going to send to DLQ..");
dlqHandler.sendToDlq(new ConsumerRecord<>("topic3", context.partition(), context.offset(), key, value), e);
}
}
#Override
public void close() {
//nothing needs to be done.
}
});
}
interface KStreamBinding {
#Input("topic3")
KStream<String, String> input();
}
Below is my exception stack:
org.apache.kafka.common.errors.SerializationException: Can't convert key of
class java.lang.String to class
org.apache.kafka.common.serialization.ByteArraySerializer specified in
key.serializer
Caused by: java.lang.ClassCastException: class java.lang.String cannot be
cast to class [B (java.lang.String and [B are in module java.base of loader
'bootstrap') at
org.apache.kafka.common.serialization.ByteArraySerializer.serialize(ByteArraySerializer.java:19) ~[kafka-clients-2.3.1.jar:na]
at org.apache.kafka.common.serialization.Serializer.serialize(Serializer.java:62) ~[kafka-clients-2.3.1.jar:na]
at org.apache.kafka.clients.producer.KafkaProducer.doSend(KafkaProducer.java:886) ~[kafka-clients-2.3.1.jar:na]
at org.apache.kafka.clients.producer.KafkaProducer.send(KafkaProducer.java:856) ~[kafka-clients-2.3.1.jar:na]
at org.springframework.kafka.core.DefaultKafkaProducerFactory$CloseSafeProducer.send(DefaultKafkaProducerFactory.java:592) ~[spring-kafka-2.3.7.RELEASE.jar:2.3.7.RELEASE]
at org.springframework.kafka.core.KafkaTemplate.doSend(KafkaTemplate.java:404) ~[spring-kafka-2.3.7.RELEASE.jar:2.3.7.RELEASE]
at org.springframework.kafka.core.KafkaTemplate.send(KafkaTemplate.java:241) ~[spring-kafka-2.3.7.RELEASE.jar:2.3.7.RELEASE]
at org.springframework.kafka.listener.DeadLetterPublishingRecoverer.publish(DeadLetterPublishingRecoverer.java:214) ~[spring-kafka-2.3.7.RELEASE.jar:2.3.7.RELEASE]
at org.springframework.kafka.listener.DeadLetterPublishingRecoverer.accept(DeadLetterPublishingRecoverer.java:159) ~[spring-kafka-2.3.7.RELEASE.jar:2.3.7.RELEASE]
at org.springframework.cloud.stream.binder.kafka.streams.SendToDlqAndContinue.sendToDlq(SendToDlqAndContinue.java:51) ~[spring-cloud-stream-binder-kafka-streams-3.0.4.RELEASE.jar:3.0.4.RELEASE]
I have read somewhere that sendToDlq was only having default producer config till a particular version however I use the latest binder version 3.0.4.RELEASE.
any leads appreciated.
As the error indicates, it expects byte array, so doing key.getBytes(), value.getBytes() should fix it.
dlqHandler.sendToDlq(new ConsumerRecord<>("topic3", context.partition(), context.offset(), key.getBytes(), value.getBytes()), e);

How to do unit test websocket with embedded jetty?

I want to write Junit UT case for my websocket serverendpoint code using embedded Jetty.
i tried things explained in below link:
JUnit test with javax.websocket on embedded Jetty throws RejectedExecutionException: NonBlockingThread
I want to test my onMessage callback for websocket.
If i dont use server.join() method then the connection closes as soon as it opens.
If i use server.join() method nothing happens after joining.
Below is My code.
Server startup code::
public class EmbeddedJettyServer {
private final int port;
private Server server;
public EmbeddedJettyServer(int port) {
this.port = port;
}
public void start() throws Exception {
server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(8080);
server.addConnector(connector);
// Setup the basic application "context" for this application at "/"
// This is also known as the handler tree (in jetty speak)
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
server.setHandler(context);
try {
// Initialize javax.websocket layer
ServerContainer wscontainer = WebSocketServerContainerInitializer.configureContext(context);
// Add WebSocket endpoint to javax.websocket layer
wscontainer.addEndpoint(WebSocketServer.class);
System.out.println("Begin start");
server.start();
server.dump(System.err);
server.join();
} catch (Throwable t) {
t.printStackTrace(System.err);
}
}
public void stop() throws Exception {
server.stop();
LOGGER.info("Jetty server stopped");
}
public URI getWebsocketUri(Class<WebSocketServer> class1) {
return server.getURI();
}
}
Client Code:
#ClientEndpoint()
public class WebSocketClientJetty {
WebSocketContainer container;
public Session connect(URI uri) throws Exception {
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
try {
// Attempt Connect
Session session = container.connectToServer(WebSocketClientJetty.class,uri);
// return container.connectToServer(WebSocketClientJetty.class, uri);
session.getBasicRemote().sendText("Hello");
// Close session
// session.close();
return session;
} finally {
}
}
public void stop() throws Exception{
if (container instanceof LifeCycle) {
((LifeCycle) container).stop();
}
}
#OnOpen
public void onWebSocketConnect(Session sess)
{
System.out.println("Socket Connected: " + sess);
}
#OnMessage
public void onWebSocketText(String message)
{
System.out.println("Received TEXT message: " + message);
}
#OnClose
public void onWebSocketClose(CloseReason reason)
{
System.out.println("Socket Closed: " + reason);
}
#OnError
public void onWebSocketError(Throwable cause)
{
cause.printStackTrace(System.err);
}
}
Serverendpoint code:
#ServerEndpoint(value = "/echo",
encoders={JsonEncoder.class})
public class WebSocketServer {
private static final Logger LOGGER =
#OnOpen
public void onOpen(Session session){
System.out.println("onopen");
some code....
}
#OnMessage
public void onMessage(String message, Session session) throws IOException{
System.out.println("onmessage");
....
}
#OnClose
public void onClose(Session session){
System.out.println("onClose");
...
}
}
Ut case:
public class WebSocketJettyTest {
private static EmbeddedJettyServer server;
#ClassRule
public static final ExternalResource integrationServer = new ExternalResource() {
#Override
protected void before() throws Throwable {
System.out.println("Starting...");
server = new EmbeddedJettyServer(8080);
server.start();
System.out.println("Started");
}
};
#Before
public void setUp() throws Exception {
}
#After
public void shutdown() throws Exception {
server.stop();
}
#Test
public void testSocket() throws Exception {
/*URI uri = server.getWebsocketUri(WebSocketServer.class);*/
URI uri = URI.create("ws://localhost:8080/echo");
WebSocketClientJetty client = new WebSocketClientJetty();
Session session = client.connect(uri);
session.getBasicRemote().sendText("hello");
Thread.sleep(6000);
client.stop();
}
}
Drop the call to
server.join();
That just makes the current thread wait until the server thread stops.
Which is making it difficult for you.

WebSocket issue : Multiple Endpoints may not be deployed to the same path

i am building project in spring boot and i want to implement chat application logic into my project i am using websockets and here is my code
#SpringBootApplication
public class SamepinchApplication extends SpringBootServletInitializer{
#Bean
public EchoEndpoint echoEndpoint() {
return new EchoEndpoint();
}
#Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
#Bean
public ServletContextAware endpointExporterInitializer(final ApplicationContext applicationContext) {
return new ServletContextAware() {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SamepinchApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(SamepinchApplication.class, args);
}
}
and EchoEndpoint
#ServerEndpoint(value = "/api/v1/chat/{username}")
public class EchoEndpoint {
private static final Logger log = LoggerFactory.getLogger(EchoEndpoint.class);
private static final Set<Session> sessionsSet = Collections.synchronizedSet(new HashSet<Session>());
private static final ConcurrentHashMap<String, Object> sessions = new ConcurrentHashMap<String, Object>();
#OnOpen
public void onWebSocketConnect(Session session, #PathParam("username") String uname) throws IOException {
session.getBasicRemote().sendText("Connection established with session id "+session.getId());
sessionsSet.add(session);
sessions.put(uname, session);
System.out.println("Connected with: " + session.getId());
log.info("Connected with: " + session.getId());
}
#OnMessage
public void onWebSocketMessage(Session session, String message) throws IOException {
System.out.println("getting message......");
System.out.println(message.substring(message.indexOf(":",0)+1));
String[] mesgArray = message.split(":");
System.out.println(mesgArray[0]);
Session sess = (Session) sessions.get(mesgArray[0]);
if(sess != null)
sess.getBasicRemote().sendText(message.substring(message.indexOf(":",0)+1));
// sendMessageToAll(message);
}
#OnClose
public void onWebSocketClose(Session session) {
System.out.println("Closed: " + session.getId());
log.info("Closed: " + session.getId());
}
#OnError
public void onWebSocketError(Session session, Throwable error) {
System.out.println("Error (from " + session.getId() + "): " + error.getMessage());
log.info("Error (from " + session.getId() + "): " + error.getMessage());
}
private void sendMessageToAll(String message){
for(Session s : sessionsSet){
try {
log.info("send from qasim siddiqui");
log.info(s.getId());
s.getBasicRemote().sendText(message);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
this code is working fine when i am running code in ecllipse but when i deployed it to tomcat it gives me this exception
SEVERE: ContainerBase.addChild: start:
org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/samepinch-0.0.1-SNAPSHOT]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:652)
at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1095)
at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1930)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalStateException: Failed to register #ServerEndpoint class: class com.samepinch.socket.EchoEndpoint
at org.springframework.web.socket.server.standard.ServerEndpointExporter.registerEndpoint(ServerEndpointExporter.java:148)
at org.springframework.web.socket.server.standard.ServerEndpointExporter.registerEndpoints(ServerEndpointExporter.java:129)
at org.springframework.web.socket.server.standard.ServerEndpointExporter.afterSingletonsInstantiated(ServerEndpointExporter.java:107)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:775)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.context.web.SpringBootServletInitializer.run(SpringBootServletInitializer.java:117)
at org.springframework.boot.context.web.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:108)
at org.springframework.boot.context.web.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:68)
at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:175)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5517)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
... 10 more
Caused by: javax.websocket.DeploymentException: Multiple Endpoints may not be deployed to the same path [/api/v1/chat/{username}]
at org.apache.tomcat.websocket.server.WsServerContainer.addEndpoint(WsServerContainer.java:199)
at org.apache.tomcat.websocket.server.WsServerContainer.addEndpoint(WsServerContainer.java:271)
at org.springframework.web.socket.server.standard.ServerEndpointExporter.registerEndpoint(ServerEndpointExporter.java:145)
... 24 more
on tomcat it tries to create multiple endpoints and i am not getting any solution . Can anybody help me!
i am using this dependency for websocket
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
you remove
#Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
Tomcat not need this
You are creating multiple end points in production,you should need echo end point in development not in production..so configure according to the environment
if (Environment.current == Environment.DEVELOPMENT) {
// then create echo point
}

Resources