public async Task <CompletionReason> ServeConnection(TaskCompletionSource <TimeSpan?> timeoutCompletionSource = null, CancellationToken cancellationToken = default(CancellationToken)) { timeoutCompletionSource = timeoutCompletionSource ?? new TaskCompletionSource <TimeSpan?>(); try { BuildRequest request; try { Log("Begin reading request."); request = await _clientConnection.ReadBuildRequest(cancellationToken).ConfigureAwait(false); Log("End reading request."); } catch (Exception e) { LogException(e, "Error reading build request."); return(CompletionReason.CompilationNotStarted); } CheckForNewKeepAlive(request, timeoutCompletionSource); // Kick off both the compilation and a task to monitor the pipe for closing. var buildCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); var compilationTask = ServeBuildRequest(request, buildCts.Token); var monitorTask = _clientConnection.CreateMonitorDisconnectTask(buildCts.Token); await Task.WhenAny(compilationTask, monitorTask).ConfigureAwait(false); // Do an 'await' on the completed task, preference being compilation, to force // any exceptions to be realized in this method for logging. CompletionReason reason; if (compilationTask.IsCompleted) { var response = await compilationTask.ConfigureAwait(false); try { Log("Begin writing response."); await _clientConnection.WriteBuildResponse(response, cancellationToken).ConfigureAwait(false); reason = CompletionReason.Completed; Log("End writing response."); } catch { reason = CompletionReason.ClientDisconnect; } } else { await monitorTask.ConfigureAwait(false); reason = CompletionReason.ClientDisconnect; } // Begin the tear down of the Task which didn't complete. buildCts.Cancel(); return(reason); } finally { _clientConnection.Close(); // Ensure that the task is completed. If the code previously added a real result this will // simply be a nop. timeoutCompletionSource.TrySetResult(null); } }
public async Task <ConnectionData> ServeConnection(CancellationToken cancellationToken = default(CancellationToken)) { try { BuildRequest request; try { Log("Begin reading request."); request = await _clientConnection.ReadBuildRequest(cancellationToken).ConfigureAwait(false); Log("End reading request."); } catch (Exception e) { LogException(e, "Error reading build request."); return(new ConnectionData(CompletionReason.CompilationNotStarted)); } var keepAlive = CheckForNewKeepAlive(request); // Kick off both the compilation and a task to monitor the pipe for closing. var buildCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); var compilationTask = ServeBuildRequest(request, buildCts.Token); var monitorTask = _clientConnection.CreateMonitorDisconnectTask(buildCts.Token); await Task.WhenAny(compilationTask, monitorTask).ConfigureAwait(false); // Do an 'await' on the completed task, preference being compilation, to force // any exceptions to be realized in this method for logging. CompletionReason reason; if (compilationTask.IsCompleted) { var response = await compilationTask.ConfigureAwait(false); try { Log("Begin writing response."); await _clientConnection.WriteBuildResponse(response, cancellationToken).ConfigureAwait(false); reason = CompletionReason.Completed; Log("End writing response."); } catch { reason = CompletionReason.ClientDisconnect; } } else { await monitorTask.ConfigureAwait(false); reason = CompletionReason.ClientDisconnect; } // Begin the tear down of the Task which didn't complete. buildCts.Cancel(); return(new ConnectionData(reason, keepAlive)); } finally { _clientConnection.Close(); } }