/// <summary> /// Starts a unary request - streamed response call. /// </summary> public void StartServerStreamingCall(TRequest msg) { lock (myLock) { bool callStartedOk = false; try { GrpcPreconditions.CheckState(!started); started = true; Initialize(details.Channel.CompletionQueue); halfcloseRequested = true; using (var serializationScope = DefaultSerializationContext.GetInitializedThreadLocalScope()) { var payload = UnsafeSerialize(msg, serializationScope.Context); streamingResponseCallFinishedTcs = new TaskCompletionSource <object>(); using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) { call.StartServerStreaming(ReceivedStatusOnClientCallback, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags); callStartedOk = true; } } call.StartReceiveInitialMetadata(ReceivedResponseHeadersCallback); } finally { if (!callStartedOk) { OnFailedToStartCallLocked(); } } } }
/// <summary> /// Sends call result status, indicating we are done with writes. /// Sending a status different from StatusCode.OK will also implicitly cancel the call. /// </summary> public Task SendStatusFromServerAsync(Status status, Metadata trailers, ResponseWithFlags?optionalWrite) { using (var serializationScope = DefaultSerializationContext.GetInitializedThreadLocalScope()) { var payload = optionalWrite.HasValue ? UnsafeSerialize(optionalWrite.Value.Response, serializationScope.Context) : SliceBufferSafeHandle.NullInstance; var writeFlags = optionalWrite.HasValue ? optionalWrite.Value.WriteFlags : default(WriteFlags); lock (myLock) { GrpcPreconditions.CheckState(started); GrpcPreconditions.CheckState(!disposed); GrpcPreconditions.CheckState(!halfcloseRequested, "Can only send status from server once."); using (var metadataArray = MetadataArraySafeHandle.Create(trailers)) { call.StartSendStatusFromServer(SendStatusFromServerCompletionCallback, status, metadataArray, !initialMetadataSent, payload, writeFlags); } halfcloseRequested = true; initialMetadataSent = true; sendStatusFromServerTcs = new TaskCompletionSource <object>(); if (optionalWrite.HasValue) { streamingWritesCounter++; } return(sendStatusFromServerTcs.Task); } } }
protected byte[] UnsafeSerialize(TWrite msg) { DefaultSerializationContext context = null; try { context = DefaultSerializationContext.GetInitializedThreadLocal(); serializer(msg, context); return(context.GetPayload()); } finally { context?.Reset(); } }
/// <summary> /// Initiates sending a message. Only one send operation can be active at a time. /// </summary> protected Task SendMessageInternalAsync(TWrite msg, WriteFlags writeFlags) { using (var serializationScope = DefaultSerializationContext.GetInitializedThreadLocalScope()) { var payload = UnsafeSerialize(msg, serializationScope.Context); lock (myLock) { GrpcPreconditions.CheckState(started); var earlyResult = CheckSendAllowedOrEarlyResult(); if (earlyResult != null) { return(earlyResult); } call.StartSendMessage(SendCompletionCallback, payload, writeFlags, !initialMetadataSent); initialMetadataSent = true; streamingWritesCounter++; streamingWriteTcs = new TaskCompletionSource <object>(); return(streamingWriteTcs.Task); } } }
/// <summary> /// Starts a unary request - unary response call. /// </summary> public Task <TResponse> UnaryCallAsync(TRequest msg) { lock (myLock) { bool callStartedOk = false; try { GrpcPreconditions.CheckState(!started); started = true; Initialize(details.Channel.CompletionQueue); halfcloseRequested = true; readingDone = true; using (var serializationScope = DefaultSerializationContext.GetInitializedThreadLocalScope()) { var payload = UnsafeSerialize(msg, serializationScope.Context); unaryResponseTcs = new TaskCompletionSource <TResponse>(); using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) { call.StartUnary(UnaryResponseClientCallback, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags); callStartedOk = true; } } return(unaryResponseTcs.Task); } finally { if (!callStartedOk) { OnFailedToStartCallLocked(); } } } }
// runs the serializer, propagating any exceptions being thrown without modifying them protected SliceBufferSafeHandle UnsafeSerialize(TWrite msg, DefaultSerializationContext context) { serializer(msg, context); return(context.GetPayload()); }
// 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; } 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()); } }
public UsageScope(DefaultSerializationContext context) { this.context = context; }
// 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()); } }