C# RestSharp-异步请求-应答模式
给出了以下情况:C# RestSharp-异步请求-应答模式,c#,rest,asynchronous,async-await,microservices,C#,Rest,Asynchronous,Async Await,Microservices,给出了以下情况: 新作业通过Post请求发送到API。此API返回作业ID和HTTP响应代码202 然后使用此作业ID请求状态终结点。如果端点在响应主体中设置了“Finished”属性,则可以继续执行步骤3 通过结果端点使用JobID查询结果,并可以对其进行处理 我的问题是我如何优雅而干净地解决这个问题。可能已经有现成的库实现了这个功能了吗?我找不到RestSharp或其他HttpClient的此类功能。 当前的解决方案如下所示: async Task PostNewJob() { var
async Task PostNewJob()
{
var restClient=新的restClient(“https://baseUrl/");
var restRequest=新的restRequest(“工作”);
//添加标题
var response=wait restClient.ExecutePostTaskAsync(restRequest);
字符串jobId=JsonConvert.DeserializeObject(response.Content);
返回jobId;
}
异步任务WaitTillJobIsReady(字符串jobId)
{
string jobStatus=string.Empty;
var-request=new-RestRequest(jobId){Method=Method.GET};
做
{
如果(!String.IsNullOrEmpty(作业状态))
Thread.Sleep(5000);//等待下一次状态更新
var response=wait restClient.ExecuteGetTaskAsync(请求,CancellationToken.None);
jobStatus=JsonConvert.DeserializeObject(response.Content);
}while(作业状态!=“完成”);
}
异步任务GetJobResponse(字符串jobID)
{
var restClient=new restClient(@“Url/bulk/”+jobID);
var restRequest=new restRequest(){Method=Method.GET};
var response=wait restClient.ExecuteGetTaskAsync(restRequest,CancellationToken.None);
dynamic downloadResponse=JsonConvert.DeserializeObject(response.Content);
var responseResult=new List(){downloadsresponse?.ToList()};
返回响应结果;
}
异步main()
{
var jobId=wait PostNewJob();
WaitTillJobIsReady(jobID.Wait();
var responseResult=等待GetJobResponse(作业ID);
//处理结果
}
正如@Paulo Morgado所说,我不应该在生产代码中使用Thread.Sleep/Task延迟。但在我看来,我必须在WaitTillJobIsReady()方法中使用它?否则我会用循环中的Get请求压倒API
针对此类问题的最佳做法是什么?长轮询 有多种方法可以处理这种类型的问题,但正如其他人已经指出的那样,RestSharp这样的库目前没有内置这种方法。在我看来,克服这一问题的首选方法是修改API以支持Nikita建议的某种类型的应用程序。这就是: 服务器保持请求打开,直到有新数据可用。一旦 如果可用,服务器将响应并发送新信息。当 客户机收到新信息后,会立即发送另一条信息 请求,然后重复该操作。这有效地模拟了 服务器推送功能 使用调度程序 不幸的是,这并不总是可能的。另一个更优雅的解决方案是创建一个检查状态的服务,然后使用诸如或之类的调度器,以重复出现的间隔(如500ms到3s)调度服务,直到成功为止。一旦它返回“Finished”属性,您就可以将任务标记为complete,以停止进程继续轮询。这可以说比您当前的解决方案更好,并且可以对正在发生的事情提供更多的控制和反馈 使用计时器 除了使用线程。睡眠,更好的选择是使用线程。这将允许您在指定的时间间隔连续调用委托,这似乎是您在这里想要做的 下面是计时器的使用示例,它将每2秒运行一次,直到达到10次运行。(摘自)
使用系统;
使用系统线程;
使用System.Threading.Tasks;
班级计划
{
专用静态定时器;
静态void Main(字符串[]参数)
{
var timerState=new timerState{Counter=0};
定时器=新定时器(
回调:新的TimerCallback(TimerTask),
州:timerState,
决斗时间:1000,
期间:2000年);
while(timerState.Counter)在async
code中不使用Thread.Sleep(…)
。使用wait Task,Delay(…)
取而代之。在生产代码中,不使用它们。使用HttpClient
而不是RestSharp。不幸的是,这并没有完全回答我的问题。如果没有线程。睡眠(…)或任务。延迟(…),我应该如何解决作业状态的轮询问题在高效的代码中?我希望节省使用GET-Requests?基本上您正在做的事情已经可以了-它被称为轮询(虽然轮询时间不长,因为您没有打开一个流)。是的,您可能需要对其进行一点重构,但这个想法是正确的,而且就我而言,没有任何库提供现成的功能。您可以在这里看到类似的内容—令人惊讶的是,没有人提到Polly。这是一个非常有用的库,用于实现重试逻辑。它有多种用途,但最简单的一种是处理响应和specify是否重试以及在重试之前等待多长时间。也就是说,正如Nikita所说,轮询很好,我通常是最简单的解决方案。Task.Delay与Thread.Sleep不同,它会将资源释放到线程池,因此我会尽可能使用Task.Delay。
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
private static Timer timer;
static void Main(string[] args)
{
var timerState = new TimerState { Counter = 0 };
timer = new Timer(
callback: new TimerCallback(TimerTask),
state: timerState,
dueTime: 1000,
period: 2000);
while (timerState.Counter <= 10)
{
Task.Delay(1000).Wait();
}
timer.Dispose();
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}: done.");
}
private static void TimerTask(object timerState)
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}: starting a new callback.");
var state = timerState as TimerState;
Interlocked.Increment(ref state.Counter);
}
class TimerState
{
public int Counter;
}
}