private void WorkImpl(TaskCompletionSource<object> taskCompletionSource) { Process: if (!Alive) { // If this subscription is dead then return immediately taskCompletionSource.TrySetResult(null); return; } var items = new List<ArraySegment<Message>>(); int totalCount; object state; PerformWork(items, out totalCount, out state); if (items.Count > 0) { var messageResult = new MessageResult(items, totalCount); Task<bool> callbackTask = Invoke(messageResult, s => BeforeInvoke(s), state); if (callbackTask.IsCompleted) { try { // Make sure exceptions propagate callbackTask.Wait(); if (callbackTask.Result) { // Sync path goto Process; } else { // If we're done pumping messages through to this subscription // then dispose Dispose(); // If the callback said it's done then stop taskCompletionSource.TrySetResult(null); } } catch (Exception ex) { if (ex.InnerException is TaskCanceledException) { taskCompletionSource.TrySetCanceled(); } else { taskCompletionSource.TrySetUnwrappedException(ex); } } } else { WorkImplAsync(callbackTask, taskCompletionSource); } } else { taskCompletionSource.TrySetResult(null); } }
private void WorkImplAsync(Task<bool> callbackTask, TaskCompletionSource<object> taskCompletionSource) { // Async path callbackTask.ContinueWith(task => { if (task.IsFaulted) { taskCompletionSource.TrySetUnwrappedException(task.Exception); } else if (task.IsCanceled) { taskCompletionSource.TrySetCanceled(); } else if (task.Result) { WorkImpl(taskCompletionSource); } else { // If we're done pumping messages through to this subscription // then dispose Dispose(); // If the callback said it's done then stop taskCompletionSource.TrySetResult(null); } }); }
private Task ProcessMessages(ITransportConnection connection, Func<Task> postReceive) { var tcs = new TaskCompletionSource<object>(); Action<Exception> endRequest = (ex) => { Trace.TraceInformation("DrainWrites(" + ConnectionId + ")"); // Drain the task queue for pending write operations so we don't end the request and then try to write // to a corrupted request object. WriteQueue.Drain().Catch().ContinueWith(task => { if (ex != null) { tcs.TrySetUnwrappedException(ex); } else { tcs.TrySetResult(null); } CompleteRequest(); Trace.TraceInformation("EndRequest(" + ConnectionId + ")"); }, TaskContinuationOptions.ExecuteSynchronously); if (AfterRequestEnd != null) { AfterRequestEnd(); } }; ProcessMessages(connection, postReceive, endRequest); return tcs.Task; }