Future<Void> method with @Gateway causes thread leak
In what version(s) of Spring Integration are you seeing this issue?
org.springframework.boot:spring-boot-starter-integration: '2.2.6.RELEASE'
Describe the bug
If response type is Future<Void>, the method with @Gateway causes thread leak. New threads are constantly spawned without reusing or disposing. It was confirmed on thread dump I collected in my application. Even though each memory usage is quite small, threads being racked up will eventually lead OOM.
I assume that this is happening because of no acknowledgement with Void.
However, there's a solution. It simply can be avoided by replacing it with void send along with ExecutorService in order to keep it asynchronous. (Non-blocking messaging is what I wanna do)
e.g.
@Bean
public MessageChannel sampleChannel() {
return new PublishSubscribeChannel(Executors.newCachedThreadPool());
}
This is maybe a bug or should be described clearly in the docs if not a bug imhp.
To Reproduce
- Register bean at a config class
@Bean
public MessageChannel sampleChannel() {
return MessageChannels.publishSubscribe().get();
}
- Make MessagingGateway have a method returns Future<Void> as following
@MessagingGateway
public interface SampleMessagingGateway {
@Gateway(requestChannel = "sampleChannel")
Future<Void> send(Payload payload);
}
-
send(payload)at a producer class. -
Have a consumer class which contains method like
@ServiceActivator(inputChannel = "sampleChannel")
public void onSample(Payload payload){
// do something
}
As a result, threads spawned by that consumers stays in the lifetime of application apparently unless the application is restarted or so. Thus this will eventually lead OOM.
Expected behavior
- It won't cause thread leak with
Future<Void>
Or
- Described in doc well. This behavior seems not described explicitly at asyn-gateway doc. If you wanna deal with it void type, the solution using
ExecutorServiceshould be recommended.
Sample
See above.
Thx in advance.
See similar discussion about Mono<Void> on Gitter: https://gitter.im/spring-projects/spring-integration?at=614aef15f428f97a9f9d0077.
I think this is that part which is missed from the logic and therefore it is not described in the docs.
At a glance it does not make much sense to have a Future<Void>, but if you build an async pipe-line and just rely on the completion of the Future as a fact, it really could be handy since even void services could be called from executors.
See more explanation here: https://stackoverflow.com/questions/50567120/what-is-futurevoid
For now I schedule this for the next version since we never advertised support for Future<Void>, so this could be treated as a new feature, but we always can change our mind and with enough justification back-port the fix to the current 5.5.x generation.
Looks like Kotlin suspend functions without return type will suffer from the same problem.
Will try to fix this shortly.