spring-cloud / spring-cloud/spring-cloud-gateway
Recycling ManagedChannel to prevent creation on every call in JsonToGrpcGatewayFilterFactory
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 4.9k
- Forks
- 3.5k
- Avg merge
- 20h 57m
- Merged PRs (30d)
- 8
Description
Is your feature request related to a problem? Please describe.
JsonToGrpcGatewayFilter which converts a json to a gRPC creates ManagedChannel on every call.
package org.springframework.cloud.gateway.filter.factory;
public class JsonToGrpcGatewayFilterFactory
extends AbstractGatewayFilterFactory<JsonToGrpcGatewayFilterFactory.Config> {
... ...
class GRPCResponseDecorator extends ServerHttpResponseDecorator {
... ...
// We are creating this on every call, should optimize?
private ManagedChannel createChannelChannel(String host, int port) {
NettyChannelBuilder nettyChannelBuilder = NettyChannelBuilder.forAddress(host, port);
try {
return grpcSslConfigurer.configureSsl(nettyChannelBuilder);
}
catch (SSLException e) {
throw new RuntimeException(e);
}
}
}
}
Furthermore, there's no logic that call shutdown() ManagedChannel.
2023-11-03T12:12:05.152+09:00 ERROR 6277 --- [ctor-http-nio-3] i.g.i.ManagedChannelOrphanWrapper :
*~*~*~ Previous channel ManagedChannelImpl{logId=7, target=localhost:8081} was not shutdown properly!!! ~*~*~*
Make sure to call shutdown()/shutdownNow() and wait until awaitTermination() returns true.
Describe the solution you'd like
So here below is my suggestion using ConcurrentHashMap to recycle ManagedChannels.
(or add something like lifecycle to manages all ManageChannels?)
Describe alternatives you've considered
package org.springframework.cloud.gateway.filter.factory;
public class JsonToGrpcGatewayFilterFactory
extends AbstractGatewayFilterFactory<JsonToGrpcGatewayFilterFactory.Config> {
// a container for ManagedChannel. key = host + ":" + port
private final ConcurrentHashMap<String, ManagedChannel> ManagedChannelContainer = new ConcurrentHashMap<>();
... ...
class GRPCResponseDecorator extends ServerHttpResponseDecorator {
... ...
// get ManageChannel from ManageChannelContainer and if it exists, return that value(ManageChannel);
// if it doesn't exist, create ManageChannel and put it in ManageChannelContainer and return it.
private ManagedChannel createChannelChannel(String host, int port) {
String key = host + ":" + port;
ManagedChannel managedChannel = ManagedChannelContainer.get(key);
if (managedChannel == null) {
NettyChannelBuilder nettyChannelBuilder = NettyChannelBuilder.forAddress(host, port);
try {
managedChannel = grpcSslConfigurer.configureSsl(nettyChannelBuilder);
ManagedChannelContainer.put(key, managedChannel);
return managedChannel;
}
catch (SSLException e) {
throw new RuntimeException(e);
}
} else {
return managedChannel;
}
}
}
}
Additional context
build.gradle
// includes spring-cloud-gateway-server:4.0.7
implementation 'org.springframework.cloud:spring-cloud-gateway-starter:4.0.7'
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading JsonToGrpcGatewayFilterFactory and tracing how GRPCResponseDecorator creates and uses ManagedChannel for each request. Define the channel ownership and lifecycle, including reuse, SSL configuration, and shutdown behavior; the work is done when channels are not recreated unnecessarily and are cleanly released.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- grpc, java, spring
- Domain
- api, backend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100