C# 如何将失败的后台异步任务重新排队
您好,我正在尝试使用C# 如何将失败的后台异步任务重新排队,c#,asp.net-core,asp.net-core-mvc,asp.net-core-2.2,C#,Asp.net Core,Asp.net Core Mvc,Asp.net Core 2.2,您好,我正在尝试使用BackgroundService创建一个在后台执行的通用任务队列服务。我避免使用DelegatefunctionFunc作为EnqueueTask(Task newTask)方法的输入,因为我想要一个通用的解决方案,所以我选择传递一个Task。但此解决方案不允许我在ExecuteAsync(CancellationToken stoppingToken)中重新排队失败的任务,因为该任务返回的ResponseHelper实例不是失败任务的副本。请帮助我更正代码,我必须从deq
BackgroundService
创建一个在后台执行的通用任务队列服务。我避免使用Delegate
functionFunc
作为EnqueueTask(Task newTask)
方法的输入,因为我想要一个通用的解决方案,所以我选择传递一个Task
。但此解决方案不允许我在ExecuteAsync(CancellationToken stoppingToken)
中重新排队失败的任务,因为该任务返回的ResponseHelper
实例不是失败任务的副本。请帮助我更正代码,我必须从dequeuetasksync(CancellationToken CancellationToken)
函数返回一个出列任务,而不是ResponseHelper
的实例
public interface ITaskQueueHelper
{
void EnqueueTask(Task<ResponseHelper> newTask);
Task<ResponseHelper> DequeueTaskAsync(CancellationToken cancellationToken);
}
public class TaskQueueHelper : ITaskQueueHelper
{
private readonly SemaphoreSlim signal;
private readonly ConcurrentQueue<Task<ResponseHelper>> taskQueue;
public TaskQueueHelper()
{
signal = new SemaphoreSlim(0);
taskQueue = new ConcurrentQueue<Task<ResponseHelper>>();
}
public void EnqueueTask(Task<ResponseHelper> newTask)
{
if (newTask == null)
{
throw new ArgumentNullException(nameof(newTask));
}
taskQueue.Enqueue(newTask);
signal.Release();
}
public async Task<ResponseHelper> DequeueTaskAsync(CancellationToken cancellationToken)
{
await signal.WaitAsync(cancellationToken);
taskQueue.TryDequeue(out var currentTask);
/*I need to return currentTask here, instead of an instance of ResponseHelper*/
return await currentTask;
}
}
public class TaskQueueService : BackgroundService
{
private readonly ITaskQueueHelper taskQueue;
private readonly ILogger<TaskQueueService> logger;
public TaskQueueService(
ITaskQueueHelper _taskQueue,
ILogger<TaskQueueService> _logger)
{
logger = _logger;
taskQueue = _taskQueue;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
ResponseHelper response = await taskQueue.DequeueTaskAsync(stoppingToken);
try
{
if (!response.Status.Equals(ResultCode.Success))
{
/*I need to re-enqueue a failed task here*/
//taskQueue.EnqueueTask(currentTask);
}
}
catch (Exception e)
{
logger.LogError(e, $"Error occurred executing {nameof(TaskQueueService)}");
}
}
}
}
公共接口ITaskQueueHelper
{
无效排队任务(任务新任务);
任务出列TaskAsync(CancellationToken CancellationToken);
}
公共类TaskQueueHelper:ITaskQueueHelper
{
专用只读信号量LIM信号;
私有只读ConcurrentQueue任务队列;
公共TaskQueueHelper()
{
信号=新信号量lim(0);
taskQueue=新的ConcurrentQueue();
}
公共void排队任务(任务newTask)
{
if(newTask==null)
{
抛出新ArgumentNullException(nameof(newTask));
}
taskQueue.Enqueue(newTask);
信号。释放();
}
公共异步任务出列TaskAsync(CancellationToken CancellationToken)
{
wait signal.WaitAsync(cancellationToken);
TryDequeue(out var currentTask);
/*我需要在这里返回currentTask,而不是ResponseHelper的实例*/
返回等待当前任务;
}
}
公共类TaskQueueService:BackgroundService
{
专用只读ITaskQueueHelper任务队列;
专用只读ILogger记录器;
公共任务队列服务(
ITaskQueueHelper\u任务队列,
ILogger(记录器)
{
记录器=_记录器;
taskQueue=\u taskQueue;
}
受保护的覆盖异步任务ExecuteAsync(CancellationToken stoppingToken)
{
同时(!stoppingToken.IsCancellationRequested)
{
ResponseHelper response=wait taskQueue.dequeuetasksync(stoppingToken);
尝试
{
如果(!response.Status.Equals(ResultCode.Success))
{
/*我需要将失败的任务重新排队*/
//taskQueue.EnqueueTask(当前任务);
}
}
捕获(例外e)
{
logger.LogError(e,$”执行{nameof(TaskQueueService)}时出错);
}
}
}
}
对于重试,您可以执行以下操作:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
ResponseHelper response = await taskQueue.DequeueTaskAsync(stoppingToken);
try
{
if (!response.Status.Equals(ResultCode.Success))
{
// Retry the task.
response = await taskQueue.DequeueTaskAsync(stoppingToken);
}
}
catch (Exception e)
{
logger.LogError(e, $"Error occurred executing {nameof(TaskQueueService)}");
}
}
}
对于重试,您可以执行以下操作:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
ResponseHelper response = await taskQueue.DequeueTaskAsync(stoppingToken);
try
{
if (!response.Status.Equals(ResultCode.Success))
{
// Retry the task.
response = await taskQueue.DequeueTaskAsync(stoppingToken);
}
}
catch (Exception e)
{
logger.LogError(e, $"Error occurred executing {nameof(TaskQueueService)}");
}
}
}
只是提醒一下,如果你需要工作,我已经成功地使用了hangfire来代替。@Sommen谢谢你的提醒,如果我没有从其他软件工程师那里得到工作,我会考虑这个问题。wel很难理解你在这里做什么。我的意思是,如果您想重新查询任务,您需要保留对它的引用,因此需要将它添加到您的响应中,或者您的调度服务应该保留对它的引用。没有别的了way@sommmen我试图使用
EnqueueTask(Task newTask)
将任务添加到队列中,而不是通过Delegate
添加任务,任务返回类型为ResponseHelper
的实例,但当dequeuetasksync(CancellationToken CancellationToken)时
函数运行返回等待当前任务代码>它返回ResponseHelper的实例,而不是当前已退出队列的任务。我希望此函数返回currentTask。这就是我需要解决的问题。因为integerTask是一个任务,所以它包含一个TResult类型的Result属性。在本例中,TResult表示整数类型。当wait应用于integerTask时,wait表达式的计算结果为integerTask的Result属性的内容。该值分配给ret变量。
来自msdn。你看,这不是怎么回事。只是提醒一下,如果你需要工作,我已经成功地使用了hangfire来代替。@Sommen谢谢你的提醒,如果我没有从其他软件工程师那里得到一份工作,我会考虑这个问题。wel很难理解你在这里做什么。我的意思是,如果您想重新查询任务,您需要保留对它的引用,因此需要将它添加到您的响应中,或者您的调度服务应该保留对它的引用。没有别的了way@sommmen我试图使用EnqueueTask(Task newTask)
将任务添加到队列中,而不是通过Delegate
添加任务,任务返回类型为ResponseHelper
的实例,但当dequeuetasksync(CancellationToken CancellationToken)时
函数运行返回等待当前任务代码>它返回ResponseHelper的实例,而不是当前已退出队列的任务。我希望此函数返回currentTask。这就是我需要解决的问题。因为integerTask是一个任务,所以它包含一个TResult类型的Result属性。在本例中,TResult表示整数类型。当wait应用于integerTask时,wait表达式的计算结果为integerTask的Result属性的内容。该值分配给ret变量。
来自msdn。你看,这不是它的工作原理。这将重试一次任务,你可以做一个while循环来做几次。还可以查看polly以重试。它是一个流行的库和.NET基础的一部分。在<代码> IaskQuealeHelpServer接口< /CudithSoad >中添加属性的想法是怎样的?code>public Task ExecutingTask{set;get;}
并分配一个出列任务的副本。然后我可以执行类似以下操作taskQueue.EnqueueTask(taskQueue.ExecutingTask)代码>。“你对这件事有什么想法吗?”我说