Open Lincong opened 2 months ago
Thanks for the detailed information. 👍
Currently, we can't reuse an ArmeriaChannel for different stubs because the jsonMarshaller must be created individually for each stub: https://github.com/line/armeria/blob/0960d091bfc7f350c17e68f57cc627de584b9705/grpc/src/main/java/com/linecorp/armeria/internal/client/grpc/GrpcClientFactory.java#L170
We would need to disable JSON conversion to reuse the channel or introduce another implementation for the Channel. Given this limitation, I think a dedicated API for creating the channel is necessary, such as GrpcClientBuilder.buildChannel()
.
Do you have any idea on this? @line/dx
Currently, we can't reuse an ArmeriaChannel for different stubs because the jsonMarshaller must be created individually for each stub
I am curious why this is the case. Is it because every jsonMarshaller
instance is associated with some stub-specific state?
I think a dedicated API for creating the channel is necessary, such as GrpcClientBuilder.buildChannel()
SG, it works for our use case. Thanks!
Is it because every jsonMarshaller instance is associated with some stub-specific state?
Yes, it is. A JSON marshaller has to know the type to serialize and deserialize. Here are links:
Maybe we could refactor ArmeriaChannel
so that it's capable of having different marshallers for different stub types? Could use weak-key map to avoid leak (if that's gonna be a problem)
Maybe we could refactor ArmeriaChannel so that it's capable of having different marshallers for different stub types?
Yeah, that's also a good idea. 👍
Hi there, we build gRPC clients with Armeria 1.16.3. I wonder whether either of the following ideas could be good:
com.linecorp.armeria.client.ClientBuilder
class expose an API to build and return aio.grpc.Channel
(implemented byArmeriaChannel
).ClientBuilder
build aio.grpc.Channel
once (at the first time whenClientBuilder#build(...)
is called) and then re-use the channel for all future invocations ofClientBuilder#build(...)
.Here is why I think these^ ideas would benefit our use case:
GrpcChannel
to our users.GrpcChannel
is not aware of any stub type. Users can create stubs fromGrpcChannel
. For example,channel.createStub[StubType](...)
.GrpcChannel
is a custom abstraction defined by my team and it is NOTio.grpc.Channel
.GrpcChannel
instance contains its ownClientBuilder
(decorators) andClientFactory
(connection pool). The goal is to have a clear separation of resources amongGrpcChannel
instances. Users can create and manageGrpcChannel
s by themselves. grpc-java provides a similar mental mode (example) to allow users to create stub(s) from aio.grpc.Channel
(a grpc-java interface/API).channel.createStub[StubType](...)
invocation requires callingClientBuilder.build(stubClass)
which creates aio.grpc.Channel
. That means when N stubs are created from ourGrpcChannel
, there are N grpc-javaio.grpc.Channel
s created (one for each stub).GrpcChannel
instance have oneio.grpc.Channel
instance from which all stubs are built.ClientBuilder
does not provide an API to buildio.grpc.Channel
. Specifically, in the POC, after the first stub was created, we callstub.getChannel
to get a reference to its underlyingio.grpc.Channel
built byClientBuilder
, then cache and reuse theio.grpc.Channel
to build future stubs. IfClientBuilder
provides an API to build and return aio.grpc.Channel
(proposed idea 1), we can get rid of the hack. Or we can consider makingClientBuilder
internally build aio.grpc.Channel
once and keep reusing it for all invocations ofClientBuilder.build(stubClass)
. With this change, our code (inGrpcChannel.createStub
) can simply callClientBuilder.build(stubClass)
to build every stub sinceClientBuilder.build(stubClass)
would be much more lightweight (because theio.grpc.Channel
is reused).Please let me know WYT. Thanks!