/// <summary> /// Try to process the request using the server. Returns a null-containing Task if a response /// from the server cannot be retrieved. /// </summary> private static async Task <ServerResponse> TryProcessRequest( Client client, ServerRequest request, CancellationToken cancellationToken) { ServerResponse response; using (client) { // Write the request try { ServerLogger.Log("Begin writing request"); await request.WriteAsync(client.Stream, cancellationToken).ConfigureAwait(false); ServerLogger.Log("End writing request"); } catch (Exception e) { ServerLogger.LogException(e, "Error writing build request."); return(new RejectedServerResponse()); } // Wait for the compilation and a monitor to detect if the server disconnects var serverCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); ServerLogger.Log("Begin reading response"); var responseTask = ServerResponse.ReadAsync(client.Stream, serverCts.Token); var monitorTask = client.WaitForDisconnectAsync(serverCts.Token); await Task.WhenAny(new[] { responseTask, monitorTask }).ConfigureAwait(false); ServerLogger.Log("End reading response"); if (responseTask.IsCompleted) { // await the task to log any exceptions try { response = await responseTask.ConfigureAwait(false); } catch (Exception e) { ServerLogger.LogException(e, "Error reading response"); response = new RejectedServerResponse(); } } else { ServerLogger.Log("Server disconnect"); response = new RejectedServerResponse(); } // Cancel whatever task is still around serverCts.Cancel(); Debug.Assert(response != null); return(response); } }
internal static async Task <ServerResponse> Send(string pipeName, ServerRequest request) { using (var client = await Client.ConnectAsync(pipeName, timeout: null, cancellationToken: default).ConfigureAwait(false)) { await request.WriteAsync(client.Stream).ConfigureAwait(false); return(await ServerResponse.ReadAsync(client.Stream).ConfigureAwait(false)); } }
protected async override Task <int> ExecuteCoreAsync() { if (!IsServerRunning()) { // server isn't running right now Out.Write("Server is not running."); return(0); } try { using (var client = await Client.ConnectAsync(Pipe.Value(), timeout: TimeSpan.FromSeconds(5), cancellationToken: Cancelled)) { if (client == null) { throw new InvalidOperationException("Couldn't connect to the server."); } var request = ServerRequest.CreateShutdown(); await request.WriteAsync(client.Stream, Cancelled).ConfigureAwait(false); var response = ((ShutdownServerResponse)await ServerResponse.ReadAsync(client.Stream, Cancelled)); if (Wait.HasValue()) { try { var process = Process.GetProcessById(response.ServerProcessId); process.WaitForExit(); } catch (Exception ex) { // There is an inherent race here with the server process. If it has already shutdown // by the time we try to access it then the operation has succeeded. Error.Write(ex); } Out.Write("Server pid:{0} shut down completed.", response.ServerProcessId); } } } catch (Exception ex) when(IsServerRunning()) { // Ignore an exception that occurred while the server was shutting down. Error.Write(ex); } return(0); }
public async Task ServerResponse_WriteRead_RoundtripsProperly() { // Arrange var response = new CompletedServerResponse(42, utf8output: false, output: "a string", error: "an error"); var memoryStream = new MemoryStream(); // Act await response.WriteAsync(memoryStream, CancellationToken.None); // Assert Assert.True(memoryStream.Position > 0); memoryStream.Position = 0; var result = (CompletedServerResponse)await ServerResponse.ReadAsync(memoryStream, CancellationToken.None); Assert.Equal(42, result.ReturnCode); Assert.False(result.Utf8Output); Assert.Equal("a string", result.Output); Assert.Equal("an error", result.ErrorOutput); }
public async Task ShutdownResponse_WriteRead_RoundtripsProperly() { // Arrange & Act 1 var memoryStream = new MemoryStream(); var response = new ShutdownServerResponse(42); // Assert 1 Assert.Equal(ServerResponse.ResponseType.Shutdown, response.Type); // Act 2 await response.WriteAsync(memoryStream, CancellationToken.None); // Assert 2 memoryStream.Position = 0; var read = await ServerResponse.ReadAsync(memoryStream, CancellationToken.None); Assert.Equal(ServerResponse.ResponseType.Shutdown, read.Type); var typed = (ShutdownServerResponse)read; Assert.Equal(42, typed.ServerProcessId); }
public async Task AcceptConnection_ShutdownRequest_ReturnsShutdownResponse() { // Arrange var stream = new TestableStream(); await ServerRequest.CreateShutdown().WriteAsync(stream.ReadStream, CancellationToken.None); stream.ReadStream.Position = 0; var connection = CreateConnection(stream); var connectionHost = CreateConnectionHost(); var compilerHost = CreateCompilerHost(); var dispatcher = new DefaultRequestDispatcher(connectionHost, compilerHost, CancellationToken.None); // Act var connectionResult = await dispatcher.AcceptConnection( Task.FromResult <Connection>(connection), accept : true, cancellationToken : CancellationToken.None); // Assert Assert.Equal(ConnectionResult.Reason.ClientShutdownRequest, connectionResult.CloseReason); stream.WriteStream.Position = 0; var response = await ServerResponse.ReadAsync(stream.WriteStream).ConfigureAwait(false); Assert.Equal(ServerResponse.ResponseType.Shutdown, response.Type); }
public async Task AcceptConnection_AcceptFalse_RejectsBuildRequest() { // Arrange var stream = new TestableStream(); await EmptyServerRequest.WriteAsync(stream.ReadStream, CancellationToken.None); stream.ReadStream.Position = 0; var connection = CreateConnection(stream); var connectionHost = CreateConnectionHost(); var compilerHost = CreateCompilerHost(); var dispatcher = new DefaultRequestDispatcher(connectionHost, compilerHost, CancellationToken.None); // Act var connectionResult = await dispatcher.AcceptConnection( Task.FromResult <Connection>(connection), accept : false, cancellationToken : CancellationToken.None); // Assert Assert.Equal(ConnectionResult.Reason.CompilationNotStarted, connectionResult.CloseReason); stream.WriteStream.Position = 0; var response = await ServerResponse.ReadAsync(stream.WriteStream).ConfigureAwait(false); Assert.Equal(ServerResponse.ResponseType.Rejected, response.Type); }
public async Task ServerRunning_CancelCompilation_CancelsSuccessfully() { // Arrange const int requestCount = 5; var count = 0; var completionSource = new TaskCompletionSource <bool>(); var host = CreateCompilerHost(c => c.ExecuteFunc = (req, ct) => { if (Interlocked.Increment(ref count) == requestCount) { completionSource.SetResult(true); } ct.WaitHandle.WaitOne(); return(new RejectedServerResponse()); }); var semaphore = new SemaphoreSlim(1); Action <object, EventArgs> onListening = (s, e) => { semaphore.Release(); }; using (var serverData = ServerUtilities.CreateServer(compilerHost: host, onListening: onListening)) { // Send all the requests. var clients = new List <Client>(); for (var i = 0; i < requestCount; i++) { // Wait for the server to start listening. await semaphore.WaitAsync(TimeSpan.FromMinutes(1)); var client = await Client.ConnectAsync(serverData.PipeName, timeout : null, cancellationToken : default); await EmptyServerRequest.WriteAsync(client.Stream); clients.Add(client); } // Act // Wait until all of the connections are being processed by the server. await completionSource.Task; // Now cancel var stats = await serverData.CancelAndCompleteAsync(); // Assert Assert.Equal(requestCount, stats.Connections); Assert.Equal(requestCount, count); // Read the server response to each client. foreach (var client in clients) { var task = ServerResponse.ReadAsync(client.Stream); // We expect this to throw because the stream is already closed. await Assert.ThrowsAnyAsync <IOException>(() => task); client.Dispose(); } } }