public async Task NoCompilationsProcessShutdown() { var host = new TestableCompilerServerHost(runCompilation: delegate { // We should never get here. Assert.False(true); throw null; }); var(clientStream, serverStream) = await CreateNamedPipePair().ConfigureAwait(false); try { var connection = new NamedPipeClientConnection(host, "identifier", serverStream); await BuildRequest.CreateShutdown().WriteAsync(clientStream).ConfigureAwait(false); var connectionData = await connection.HandleConnection(allowCompilationRequests : false).ConfigureAwait(false); Assert.Equal(CompletionReason.ClientShutdownRequest, connectionData.CompletionReason); Assert.Null(connectionData.KeepAlive); var response = await BuildResponse.ReadAsync(clientStream); Assert.Equal(BuildResponse.ResponseType.Shutdown, response.Type); } finally { clientStream.Close(); serverStream.Close(); } }
public async Task ShutdownRequest(bool allowCompilationRequests) { var hitCompilation = false; var compilerServerHost = new TestableCompilerServerHost(delegate { hitCompilation = true; throw new Exception(""); }); BuildResponse?response = null; var clientConnectionHandler = new ClientConnectionHandler(compilerServerHost); var clientConnection = new TestableClientConnection() { ReadBuildRequestFunc = _ => Task.FromResult(BuildRequest.CreateShutdown()), WriteBuildResponseFunc = (r, _) => { response = r; return(Task.CompletedTask); } }; var completionData = await clientConnectionHandler.ProcessAsync( Task.FromResult <IClientConnection>(clientConnection), allowCompilationRequests : allowCompilationRequests).ConfigureAwait(false); Assert.False(hitCompilation); Assert.Equal(new CompletionData(CompletionReason.RequestCompleted, shutdownRequested: true), completionData); Assert.True(response is ShutdownBuildResponse); }
internal async Task <int> SendShutdownAsync(CancellationToken cancellationToken = default) { var response = await SendAsync(BuildRequest.CreateShutdown(), cancellationToken) .ConfigureAwait(false); return(((ShutdownBuildResponse)response).ServerProcessId); }
public void MutexAcquiredWhenRunningServer() { var pipeName = Guid.NewGuid().ToString("N"); var mutexName = BuildServerConnection.GetServerMutexName(pipeName); var host = new TestableClientConnectionHost(); bool?wasServerMutexOpen = null; host.Add( () => { // Use a thread instead of Task to guarantee this code runs on a different // thread and we can validate the mutex state. var tcs = new TaskCompletionSource <IClientConnection>(); var thread = new Thread( _ => { wasServerMutexOpen = BuildServerConnection.WasServerMutexOpen( mutexName ); var client = new TestableClientConnection() { ReadBuildRequestFunc = _ => Task.FromResult(ProtocolUtil.EmptyCSharpBuildRequest), WriteBuildResponseFunc = (r, _) => Task.CompletedTask, }; tcs.SetResult(client); } ); thread.Start(); return(tcs.Task); } ); host.Add( () => { var client = new TestableClientConnection() { ReadBuildRequestFunc = _ => Task.FromResult(BuildRequest.CreateShutdown()), WriteBuildResponseFunc = (r, _) => Task.CompletedTask, }; return(Task.FromResult <IClientConnection>(client)); } ); var result = BuildServerController.CreateAndRunServer( pipeName, clientConnectionHost: host, keepAlive: TimeSpan.FromMilliseconds(-1) ); Assert.Equal(CommonCompiler.Succeeded, result); Assert.True(wasServerMutexOpen); }
public async Task ShutdownRequestWriteRead() { var memoryStream = new MemoryStream(); var request = BuildRequest.CreateShutdown(); await request.WriteAsync(memoryStream, CancellationToken.None); memoryStream.Position = 0; var read = await BuildRequest.ReadAsync(memoryStream, CancellationToken.None); VerifyShutdownRequest(read); }
/// <summary> /// Shutting down the server is an inherently racy operation. The server can be started or stopped by /// external parties at any time. /// /// This function will return success if at any time in the function the server is determined to no longer /// be running. /// </summary> internal async Task <int> RunShutdownAsync(string pipeName, bool waitForProcess = true, TimeSpan?timeout = null, CancellationToken cancellationToken = default(CancellationToken)) { if (WasServerRunning(pipeName) == false) { // The server holds the mutex whenever it is running, if it's not open then the // server simply isn't running. return(CommonCompiler.Succeeded); } try { var realTimeout = timeout != null ? (int)timeout.Value.TotalMilliseconds : Timeout.Infinite; using (var client = await ConnectForShutdownAsync(pipeName, realTimeout).ConfigureAwait(false)) { var request = BuildRequest.CreateShutdown(); await request.WriteAsync(client, cancellationToken).ConfigureAwait(false); var response = await BuildResponse.ReadAsync(client, cancellationToken).ConfigureAwait(false); var shutdownResponse = (ShutdownBuildResponse)response; if (waitForProcess) { try { var process = Process.GetProcessById(shutdownResponse.ServerProcessId); process.WaitForExit(); } catch (Exception) { // 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 succeed. } } } return(CommonCompiler.Succeeded); } catch (Exception) { if (WasServerRunning(pipeName) == false) { // If the server was in the process of shutting down when we connected then it's reasonable // for an exception to happen. If the mutex has shutdown at this point then the server // is shut down. return(CommonCompiler.Succeeded); } return(CommonCompiler.Failed); } }
public void ShutdownMessage() { var request = BuildRequest.CreateShutdown(); VerifyShutdownRequest(request); Assert.Equal(1, request.Arguments.Count); var argument = request.Arguments[0]; Assert.Equal(BuildProtocolConstants.ArgumentId.Shutdown, argument.ArgumentId); Assert.Equal(0, argument.ArgumentIndex); Assert.Equal("", argument.Value); }
public async Task NoCompilationsProcessShutdown() { var stream = new TestableStream(); await BuildRequest.CreateShutdown().WriteAsync(stream.ReadStream, CancellationToken.None).ConfigureAwait(true); stream.ReadStream.Position = 0; var connection = CreateConnection(stream); var connectionData = await connection.HandleConnection(allowCompilationRequests : false).ConfigureAwait(false); Assert.Equal(CompletionReason.ClientShutdownRequest, connectionData.CompletionReason); stream.WriteStream.Position = 0; var response = await BuildResponse.ReadAsync(stream.WriteStream).ConfigureAwait(false); Assert.Equal(BuildResponse.ResponseType.Shutdown, response.Type); }
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: null, cancellationToken: Cancelled)) { var request = BuildRequest.CreateShutdown(); await request.WriteAsync(client.Stream, Cancelled).ConfigureAwait(false); var response = ((ShutdownBuildResponse)await BuildResponse.ReadAsync(client.Stream, Cancelled)); if (Wait.HasValue()) { try { var process = Process.GetProcessById(response.ServerProcessId); process.WaitForExit(); } catch (Exception) { // 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 succeed. } Out.Write("Server pid:{0} shut down", response.ServerProcessId); } } } catch (Exception) when(IsServerRunning()) { // Ignore an exception that occurred while the server was shutting down. } return(0); }
internal static async Task <int> SendShutdown(string pipeName) { var response = await Send(pipeName, BuildRequest.CreateShutdown()); return(((ShutdownBuildResponse)response).ServerProcessId); }