spring-cloud-sleuth: Error sending STOMP message via websocket

While upgrading from Spring Boot 2.0.5 to 2.1.1, I encountered a problem in a service which sends STOMP messages via a web socket. I have isolated the problem and created an example project:

https://github.com/purple52/websocket-sleuth-test

If you build that project and run the test using ./gradlew clean build --info, it’ll fail with this error:

2019-01-17 10:01:14.876 ERROR [websocket-sleuth-test,86b7bbc97c2ae296,14d3361a3e31673e,false] 6022 --- [    Test worker] o.s.m.s.b.SimpleBrokerMessageHandler     : Failed to send GenericMessage [payload=byte[16], headers={spanTraceId=86b7bbc97c2ae296, spanId=86b7bbc97c2ae296, simpMessageType=MESSAGE, nativeHeaders={spanTraceId=[86b7bbc97c2ae296], spanId=[86b7bbc97c2ae296], spanSampled=[0]}, spanSampled=0, contentType=application/json;charset=UTF-8, simpDestination=/topic/foo}]
2019-01-17 10:01:14.877 ERROR [websocket-sleuth-test,86b7bbc97c2ae296,86b7bbc97c2ae296,false] 6022 --- [    Test worker] o.s.m.s.ExecutorSubscribableChannel      : Exception from afterMessageHandled in org.springframework.cloud.sleuth.instrument.messaging.TracingChannelInterceptor@3d415f8

I am not 100% sure this is a Cloud Sleuth defect, or whether it’s Spring Messaging at fault, but I’m starting by reporting it here, since my test passes if I remove Cloud Sleuth from the project. This is using version 2.0.2-RELEASE of Cloud Sleuth, but still happens if I override and use 2.1.0-RC3.

What appears to happen is that TracingChannelInterceptor tries to remove the trace headers by calling NativeMessageHeaderAccessor.removeNativeHeader which checks that the headers are mutable, then tries to remove the native header. However, although the accessor says it is mutable, the native headers are returned in an unmodifiable map which throws an UnsupportedOperationException when the attempt is made to remove the headers.

You can see the full exception thrown with a breakpoint at AbstractMessageChannel.java#L142. Here’s the stacktrace:

java.lang.UnsupportedOperationException
	at java.util.Collections$UnmodifiableMap.remove(Collections.java:1460)
	at org.springframework.messaging.support.NativeMessageHeaderAccessor.removeNativeHeader(NativeMessageHeaderAccessor.java:209)
	at org.springframework.cloud.sleuth.instrument.messaging.MessageHeaderPropagation.removeAnyTraceHeaders(MessageHeaderPropagation.java:158)
	at org.springframework.cloud.sleuth.instrument.messaging.TracingChannelInterceptor.preSend(TracingChannelInterceptor.java:135)
	at org.springframework.messaging.support.AbstractMessageChannel$ChannelInterceptorChain.applyPreSend(AbstractMessageChannel.java:178)
	at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:132)
	at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:122)
	at org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler.lambda$sendMessageToSubscribers$0(SimpleBrokerMessageHandler.java:401)
	at java.util.Map.forEach(Map.java:630)
	at org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler.sendMessageToSubscribers(SimpleBrokerMessageHandler.java:388)
	at org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler.handleMessageInternal(SimpleBrokerMessageHandler.java:304)
	at org.springframework.messaging.simp.broker.AbstractBrokerMessageHandler.handleMessage(AbstractBrokerMessageHandler.java:256)
	at org.springframework.messaging.support.ExecutorSubscribableChannel$SendTask.run(ExecutorSubscribableChannel.java:144)
	at org.springframework.messaging.support.ExecutorSubscribableChannel.sendInternal(ExecutorSubscribableChannel.java:100)
	at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:136)
	at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:122)
	at org.springframework.messaging.simp.SimpMessagingTemplate.sendInternal(SimpMessagingTemplate.java:187)
	at org.springframework.messaging.simp.SimpMessagingTemplate.doSend(SimpMessagingTemplate.java:162)
	at org.springframework.messaging.simp.SimpMessagingTemplate.doSend(SimpMessagingTemplate.java:48)
	at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:109)
	at org.springframework.messaging.core.AbstractMessageSendingTemplate.convertAndSend(AbstractMessageSendingTemplate.java:151)
	at org.springframework.messaging.core.AbstractMessageSendingTemplate.convertAndSend(AbstractMessageSendingTemplate.java:129)
	at org.springframework.messaging.core.AbstractMessageSendingTemplate.convertAndSend(AbstractMessageSendingTemplate.java:122)
	at com.example.WebsocketTest.Can pass message via websocket(WebsocketTest.kt:69)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
	at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 24 (7 by maintainers)

Commits related to this issue

Most upvoted comments

I’m working on this as we speak. The workaround is to disable Sleuth’s websocket messaging support via spring.sleuth.integration.websockets.enabled=false