So, before going forward, here is the expected use:
- Metadata objects are cheap, make new ones per RPC call
- Metadata objects are mutable and not threadsafe.
- Once you pass the Metadata to our API (ClientCall or
ClientInterceptor), you must consider it untouchable. You cannot modify it
or any of the objects set on it any more.
- Once you get a Metadata object back from our API, it is yours. We
promise to never touch it again.
In addition, ClientInterceptors are cheap to make too, so you can
presumably make a new one per call. Depending on your exact use, you can
create a new one next to each stub call, which a reference to a Metadata in
the scope of the closure. That will make sure the metadata for each call
doesn't interfere with other calls.
We use AtomicReference in that code mainly as a way to get an indirection.
Basically, a pointer. Unless you have some performance concerns, making
a new Interceptor each time would be the right thing.
On Friday, January 27, 2017 at 6:12:29 AM UTC-8, Alex wrote:
>
> Hello,
>
> I'm trying to get my head around how to use request and response metadata
> while working with grpc stubs in multithreaded environment ( i.e. multiple
> threads hitting same stub at same time ), I found this example in one of
> gRPC tests:
>
> AtomicReference<Metadata> trailersCapture = new
> AtomicReference<Metadata>();
> AtomicReference<Metadata> headersCapture = new
> AtomicReference<Metadata>();
> stub = MetadataUtils.captureMetadata(stub, headersCapture,
> trailersCapture);
>
> assertNotNull(stub.emptyCall(EMPTY));
>
> // Assert that our side channel object is echoed back in both headers
> and trailers
> Assert.assertEquals(contextValue,
> headersCapture.get().get(METADATA_KEY));
> Assert.assertEquals(contextValue,
> trailersCapture.get().get(METADATA_KEY));
>
> Looking into Metadata utils, I can see it creates an interceptor, which
> sets the state of headersCapture/trailersCapture upon headers coming:
>
> public static ClientInterceptor newCaptureMetadataInterceptor(final
> AtomicReference<Metadata> headersCapture, final AtomicReference<Metadata>
> trailersCapture) {
> return new ClientInterceptor() {
> public <ReqT, RespT> ClientCall<ReqT, RespT>
> interceptCall(MethodDescriptor<ReqT, RespT> method, CallOptions callOptions,
> Channel next) {
> return new SimpleForwardingClientCall(next.newCall(method,
> callOptions)) {
> public void start(final Listener<RespT> responseListener,
> Metadata headers) {
> headersCapture.set((Object)null);
>
> trailersCapture.set((Object)null);
>
> super.start(new
> SimpleForwardingClientCallListener(responseListener) {
> public void onHeaders(Metadata headers) {
> headersCapture.set(headers);
> super.onHeaders(headers);
> [...]
> }
>
>
> As far as I'm concerned, this might work well when stub is called by one
> thread, but because we share headersCapture state, it will get overwritten
> ( or it won't and I'm not seeing something? )
> My main question is : How can i setup a stub, that will be thread-safe,
> and able to return correct metadata headers back to the each caller?
>
>
>
--
You received this message because you are subscribed to the Google Groups
"grpc.io" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/grpc-io.
To view this discussion on the web visit
https://groups.google.com/d/msgid/grpc-io/bbf5ed37-c734-4557-8213-f65396643512%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.