// TODO: this method is not Async, so it shouldn't be in AsyncCall class, but // it is reusing fair amount of code in this class, so we are leaving it here. /// <summary> /// Blocking unary request - unary response call. /// </summary> public TResponse UnaryCall(TRequest msg) { var profiler = Profilers.ForCurrentThread(); using (profiler.NewScope("AsyncCall.UnaryCall")) using (CompletionQueueSafeHandle cq = CompletionQueueSafeHandle.CreateSync()) { bool callStartedOk = false; try { unaryResponseTcs = new TaskCompletionSource <TResponse>(); lock (myLock) { GrpcPreconditions.CheckState(!started); started = true; Initialize(cq); halfcloseRequested = true; readingDone = true; } byte[] payload = UnsafeSerialize(msg); using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) { var ctx = details.Channel.Environment.BatchContextPool.Lease(); try { call.StartUnary(ctx, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags); callStartedOk = true; var ev = cq.Pluck(ctx.Handle); bool success = (ev.success != 0); try { using (profiler.NewScope("AsyncCall.UnaryCall.HandleBatch")) { HandleUnaryResponse(success, ctx.GetReceivedStatusOnClient(), ctx.GetReceivedMessageReader(), ctx.GetReceivedInitialMetadata()); } } catch (Exception e) { Logger.Error(e, "Exception occurred while invoking completion delegate."); } } finally { ctx.Recycle(); } } } finally { if (!callStartedOk) { lock (myLock) { OnFailedToStartCallLocked(); } } } // Once the blocking call returns, the result should be available synchronously. // Note that GetAwaiter().GetResult() doesn't wrap exceptions in AggregateException. return(unaryResponseTcs.Task.GetAwaiter().GetResult()); } }
// TODO: this method is not Async, so it shouldn't be in AsyncCall class, but // it is reusing fair amount of code in this class, so we are leaving it here. /// <summary> /// Blocking unary request - unary response call. /// </summary> public TResponse UnaryCall(TRequest msg) { var profiler = Profilers.ForCurrentThread(); using (profiler.NewScope("AsyncCall.UnaryCall")) // Create a pluckable completion queue for the call. Avoid creating a completion queue when we know the channel has already // been shutdown. In such case, the call will fail with ObjectDisposedException immediately anyway and creating / destroying // a completion queue would lead to crash if this was the last channel in the application (and thus GrpcEnvironment has been shutdown). // See https://github.com/grpc/grpc/issues/19090 using (CompletionQueueSafeHandle cq = details.Channel.Handle.IsClosed ? null : CompletionQueueSafeHandle.CreateSync()) { bool callStartedOk = false; try { unaryResponseTcs = new TaskCompletionSource <TResponse>(); lock (myLock) { GrpcPreconditions.CheckState(!started); started = true; Initialize(cq); halfcloseRequested = true; readingDone = true; } using (var serializationScope = DefaultSerializationContext.GetInitializedThreadLocalScope()) using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) { var payload = UnsafeSerialize(msg, serializationScope.Context); // do before metadata array? var ctx = details.Channel.Environment.BatchContextPool.Lease(); try { call.StartUnary(ctx, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags); callStartedOk = true; var ev = cq.Pluck(ctx.Handle); bool success = (ev.success != 0); try { using (profiler.NewScope("AsyncCall.UnaryCall.HandleBatch")) { HandleUnaryResponse(success, ctx.GetReceivedStatusOnClient(), ctx.GetReceivedMessageReader(), ctx.GetReceivedInitialMetadata()); } } catch (Exception e) { Logger.Error(e, "Exception occurred while invoking completion delegate."); } } finally { ctx.Recycle(); } } } finally { if (!callStartedOk) { lock (myLock) { OnFailedToStartCallLocked(); } } } // Once the blocking call returns, the result should be available synchronously. // Note that GetAwaiter().GetResult() doesn't wrap exceptions in AggregateException. return(unaryResponseTcs.Task.GetAwaiter().GetResult()); } }