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); }
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); }
private static async Task <ServerResponse> RunOnServerCore( IList <string> arguments, ServerPaths serverPaths, string pipeName, string keepAlive, int?timeoutOverride, TryCreateServerCoreDelegate <string, string, int?, bool, bool> tryCreateServerFunc, CancellationToken cancellationToken, bool debug) { if (pipeName == null) { return(new RejectedServerResponse()); } if (serverPaths.TempDirectory == null) { return(new RejectedServerResponse()); } var clientDir = serverPaths.ClientDirectory; var timeoutNewProcess = timeoutOverride ?? TimeOutMsNewProcess; var timeoutExistingProcess = timeoutOverride ?? TimeOutMsExistingProcess; var clientMutexName = MutexName.GetClientMutexName(pipeName); Task <Client> pipeTask = null; Mutex clientMutex = null; var holdsMutex = false; try { try { clientMutex = new Mutex(initiallyOwned: true, name: clientMutexName, createdNew: out holdsMutex); } catch (Exception ex) { // The Mutex constructor can throw in certain cases. One specific example is docker containers // where the /tmp directory is restricted. In those cases there is no reliable way to execute // the server and we need to fall back to the command line. // Example: https://github.com/dotnet/roslyn/issues/24124 ServerLogger.LogException(ex, "Client mutex creation failed."); return(new RejectedServerResponse()); } if (!holdsMutex) { try { holdsMutex = clientMutex.WaitOne(timeoutNewProcess); if (!holdsMutex) { return(new RejectedServerResponse()); } } catch (AbandonedMutexException) { holdsMutex = true; } } // Check for an already running server var serverMutexName = MutexName.GetServerMutexName(pipeName); var wasServerRunning = WasServerMutexOpen(serverMutexName); var timeout = wasServerRunning ? timeoutExistingProcess : timeoutNewProcess; if (wasServerRunning || tryCreateServerFunc(clientDir, pipeName, out var _, debug)) { pipeTask = Client.ConnectAsync(pipeName, TimeSpan.FromMilliseconds(timeout), cancellationToken); } } finally { if (holdsMutex) { clientMutex?.ReleaseMutex(); } clientMutex?.Dispose(); } if (pipeTask != null) { var client = await pipeTask.ConfigureAwait(false); if (client != null) { var request = ServerRequest.Create( serverPaths.WorkingDirectory, serverPaths.TempDirectory, arguments, keepAlive); return(await TryProcessRequest(client, request, cancellationToken).ConfigureAwait(false)); } } return(new RejectedServerResponse()); }
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(); } } }
private static async Task <ServerResponse> RunOnServerCore( IList <string> arguments, ServerPaths buildPaths, string pipeName, string keepAlive, int?timeoutOverride, Func <string, string, bool, bool> tryCreateServerFunc, CancellationToken cancellationToken, bool debug) { if (pipeName == null) { return(new RejectedServerResponse()); } if (buildPaths.TempDirectory == null) { return(new RejectedServerResponse()); } var clientDir = buildPaths.ClientDirectory; var timeoutNewProcess = timeoutOverride ?? TimeOutMsNewProcess; var timeoutExistingProcess = timeoutOverride ?? TimeOutMsExistingProcess; var clientMutexName = MutexName.GetClientMutexName(pipeName); Task <Client> pipeTask = null; using (var clientMutex = new Mutex(initiallyOwned: true, name: clientMutexName, createdNew: out var holdsMutex)) { try { if (!holdsMutex) { try { holdsMutex = clientMutex.WaitOne(timeoutNewProcess); if (!holdsMutex) { return(new RejectedServerResponse()); } } catch (AbandonedMutexException) { holdsMutex = true; } } // Check for an already running server var serverMutexName = MutexName.GetServerMutexName(pipeName); var wasServerRunning = WasServerMutexOpen(serverMutexName); var timeout = wasServerRunning ? timeoutExistingProcess : timeoutNewProcess; if (wasServerRunning || tryCreateServerFunc(clientDir, pipeName, debug)) { pipeTask = Client.ConnectAsync(pipeName, TimeSpan.FromMilliseconds(timeout), cancellationToken); } } finally { if (holdsMutex) { clientMutex.ReleaseMutex(); } } } if (pipeTask != null) { var client = await pipeTask.ConfigureAwait(false); if (client != null) { var request = ServerRequest.Create( buildPaths.WorkingDirectory, buildPaths.TempDirectory, arguments, keepAlive); return(await TryProcessRequest(client, request, cancellationToken).ConfigureAwait(false)); } } return(new RejectedServerResponse()); }