/// <inheritdoc /> public Task <IIpcResult> Send(IIpcOperation operation) { Contract.Requires(operation != null); var request = new Request(operation); // Must add the request to the m_pendingRequest dictionary before posting it to m_sendRequestBlock // Otherwise, the following can happen: // 1) the request is posted // 2) the request is picked up from the queue and processed // 3) the request handler looks up corresponding completionSource in the dictionary which is not there yet (ERROR) // 4) the TaskCompletionSource is added to the dictionary var completionSource = TaskSourceSlim.Create <IIpcResult>(); m_pendingRequests[request.Id] = completionSource; operation.Timestamp.Request_BeforePostTime = DateTime.UtcNow; bool posted = m_sendRequestBlock.Post(request); if (!posted) { // if the request was not posted: // (1) remove it from the dictionary TaskSourceSlim <IIpcResult> src; m_pendingRequests.TryRemove(request.Id, out src); // (2) complete it (with TransmissionError) completionSource.TrySetResult(new IpcResult( IpcResultStatus.TransmissionError, "Could not post IPC request: the client has already terminated.")); } return(completionSource.Task); }
private async Task <IIpcResult> ParseAndExecuteCommandAsync(int id, IIpcOperation operation) { string cmdLine = operation.Payload; m_logger.Verbose($"Command received. Request #{id}, CommandLine: {cmdLine}"); ConfiguredCommand conf; using (m_counters.StartStopwatch(DaemonCounter.ParseArgsDuration)) { conf = ParseArgs(cmdLine, m_parser); } IIpcResult result; using (var duration = m_counters.StartStopwatch(DaemonCounter.ServerActionDuration)) { result = await conf.Command.ServerAction(conf, this); result.ActionDuration = duration.Elapsed; } TimeSpan queueDuration = operation.Timestamp.Daemon_BeforeExecuteTime - operation.Timestamp.Daemon_AfterReceivedTime; m_counters.AddToCounter(DaemonCounter.QueueDurationMs, (long)queueDuration.TotalMilliseconds); return(result); }
private Request(int id, IIpcOperation operation) { Contract.Requires(operation != null); Id = id; Operation = operation; }
/// <nodoc/> public Request(IIpcOperation operation) { Contract.Requires(operation != null); Id = Interlocked.Increment(ref s_requestIdCounter); Operation = operation; }
/// <summary> /// Asynchronously serializes given <see cref="IIpcOperation"/> to a stream writer. /// </summary> /// <remarks> /// Doesn't handle any exceptions. /// </remarks> public static async Task SerializeAsync(Stream stream, IIpcOperation op, CancellationToken token) { await Utils.WriteBooleanAsync(stream, op.ShouldWaitForServerAck, token); await Utils.WriteStringAsync(stream, op.Payload, token); await stream.FlushAsync(token); }
/// <summary> /// 1. serializes an <see cref="IIpcOperation"/> over via <paramref name="stream"/>; /// 2. if the operation is synchronous, reads an <see cref="IIpcResult"/> from <paramref name="stream"/>. /// </summary> internal static async Task <IIpcResult> SendOperationAndExecuteRemotelyAsync(IIpcOperation operation, Stream stream, CancellationToken token) { await IpcOperation.SerializeAsync(stream, operation, token); return(operation.ShouldWaitForServerAck ? await IpcResult.DeserializeAsync(stream, token) : IpcResult.Success()); }
/// <inheritdoc/> /// <remarks> /// Connects to server over TCP/IP, then serializes given <paramref name="operation"/> /// (<see cref="IpcOperation.SerializeAsync(Stream, IIpcOperation, CancellationToken)"/>) /// and sends it over TCP/IP <see cref="Stream"/>. /// </remarks> Task <IIpcResult> IClient.Send(IIpcOperation operation) { Contract.Requires(operation != null); return(ConnectAndExecute((stream) => { return Utils.SendOperationAndExecuteRemotelyAsync(operation, stream, CancellationToken.None); })); }
async Task <IIpcResult> IIpcOperationExecutor.ExecuteAsync(IIpcOperation op) { Contract.Requires(op != null); Tracing.Logger.Log.ApiServerOperationReceived(m_loggingContext, op.Payload); var maybeIpcResult = await TryDeserialize(op.Payload) .ThenAsync(cmd => TryExecuteCommand(cmd)); return(maybeIpcResult.Succeeded ? maybeIpcResult.Result : new IpcResult(IpcResultStatus.ExecutionError, maybeIpcResult.Failure.Describe())); }
/// <summary> /// 1. deserializes an <see cref="IIpcOperation"/> from a given <paramref name="stream"/>; /// 2. executes the operation (via <paramref name="executor"/>); /// 3. serializes and sends back the result via <paramref name="stream"/>. /// /// If executing the operation (via <paramref name="executor"/>) fails, the <see cref="IIpcResult.ExitCode"/> /// of the result is <see cref="IpcResultStatus.ExecutionError"/> /// </summary> internal static async Task <IIpcResult> ReceiveOperationAndExecuteLocallyAsync(Stream stream, IIpcOperationExecutor executor, CancellationToken token) { IIpcOperation operation = await IpcOperation.DeserializeAsync(stream, token); IIpcResult result = await HandleExceptionsAsync(IpcResultStatus.ExecutionError, () => executor.ExecuteAsync(operation)); if (operation.ShouldWaitForServerAck) { await IpcResult.SerializeAsync(stream, result, token); } return(result); }
/// <inheritdoc /> public async Task <IIpcResult> Send(IIpcOperation operation) { Contract.Requires(operation != null); var maybeClient = await m_multiplexingClientLazyTask.Value; if (maybeClient.Succeeded) { return(await maybeClient.Result.Send(operation)); } else { return(new IpcResult(IpcResultStatus.ConnectionError, "Failing this client because creating multiplexing client failed" + maybeClient.Failure.Describe())); } }
Task <IIpcResult> IClient.Send(IIpcOperation operation) { Contract.Requires(operation != null); if (InternalClient != null) { if (global::BuildXL.Ipc.ExternalApi.Commands.Command.Deserialize(operation.Payload) is RegisterFilesForBuildManifestCommand) { // Override for RegisterFileForBuildManifestCommand (Always true) return(Task.FromResult(SendFn(operation))); } else { return(InternalClient.Send(operation)); } } return(Task.FromResult(SendFn(operation))); }
Task <IIpcResult> IClient.Send(IIpcOperation operation) { Contract.Requires(operation != null); return(Task.FromResult(SendFn(operation))); }
Task <IIpcResult> IIpcOperationExecutor.ExecuteAsync(int id, IIpcOperation operation) { Contract.Requires(operation != null); return(ParseAndExecuteCommandAsync(id, operation)); }
/// <summary> /// Always returns <see cref="IIpcResult.Success(string)"/> echoing the payload received in <paramref name="operation"/>. /// </summary> public Task <IIpcResult> Send(IIpcOperation operation) { Contract.Requires(operation != null); return(Task.FromResult((IIpcResult) new IpcResult(m_status, operation.Payload))); }
protected static IIpcResult SendWithTimeout(IClient client, IIpcOperation op) { var sendTask = client.Send(op); return(sendTask.GetAwaiter().GetResult()); }
/// <inheritdoc /> public Task <IIpcResult> ExecuteAsync(int id, IIpcOperation op) { Contract.Requires(op != null); return(Task.FromResult(m_executor(op))); }