本地进程输出的 grpc-dotnet 服务器流



我正在使用 grpc-dotnet 在 3.1 中用于一个项目。 在服务器端,grpc 调用将执行本地系统进程(例如二进制文件或脚本(。 我遇到的问题是将重定向的输出从进程流式传输回 grpc 客户端。 我现在得到的只是第一行输出。 这是我的测试代码。

public override async Task ExecuteProcess(ProcessRequest request, IServerStreamWriter<ProcessReply> responseStream, ServerCallContext context)
{
_logger.LogInformation($"Received Execution request for {request.Name}");
_logger.LogInformation($"Received Args {request.Args}");
using (var process = new Process())
{
process.StartInfo.FileName = @"cmd.exe";
process.StartInfo.Arguments = @"/c dir";      // print the current working directory information
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
//process.OutputDataReceived += async(sender, e) => await responseStream.WriteAsync(new ProcessReply { Message = e.Data });
process.OutputDataReceived += (sender, e) => ShowOutput(e.Data, responseStream)
process.Start();
process.BeginOutputReadLine();
//process.BeginErrorReadLine();
var exited = process.WaitForExit(1000 * 10);     // (optional) wait up to 10 second
}
//return Task.FromResult(new ProcessReply { Message = "Executed " + request.Name });
await responseStream.WriteAsync(new ProcessReply
{
Message = "Process Complete"
});
}
private async Task ShowOutput(string data, IServerStreamWriter<ProcessReply> responseStream)
{
if (data != null)
{
_logger.LogInformation($"Process Output {data}");
await responseStream.WriteAsync(new ProcessReply { Message = data });
}
}

在客户端,我只是使用流服务器示例代码从流中读取行。

await foreach (var message in call.ResponseStream.ReadAllAsync())
{
Console.WriteLine("Server Out: " + message.Message);
}

任何想法为什么我只从重定向的过程输出中获得 1 行进程输出。 我也只看到记录器输出中的一行。

这可能是因为你从事件处理程序写入ResponseStream,而事件处理程序不一定在流的正确异步上下文中调用。

看看 CliWrap,它将整个流程执行的东西包装在一个非常好的 API 中,包括一个返回一个IAsyncEnumerableListenAsync方法,您可以await foreach该并将输出写入流。

借用自述文件,它看起来像这样:

var cmd = Cli.Wrap("cmd.exe").WithArguments("/c dir");
await foreach (var cmdEvent in cmd.ListenAsync())
{
switch (cmdEvent)
{
case StandardOutputCommandEvent stdOut:
await responseStream.WriteAsync(new ProcessReply { Message = stdOut.Text });
break;
}
}
await responseStream.WriteAsync(new ProcessReply { Message = "Process Complete" });

最新更新