首页 > 解决方案 > 可以在没有等待的情况下运行 aspnetcore api 控制器“丢失”任务吗?

问题描述

我在进程、线程等之间有点迷失了。

本质上,我只是想找到一种对传入请求执行某些操作的标准方式,这可能需要 5-300 秒,而客户端不必等待那么长时间才能得到响应。

给定下面的代码,可以吞下任何调用长时间运行方法的编号方式吗?就像,这会发生吗?

  1. 输入端点(第二个 0)
  2. 开始长时间运行的任务
  3. 返回响应(秒2)
  4. 在第 2 秒?5? 30?这...实例/线程/调用/执行环境刚刚关闭,因为它“完成”了。我“完成”了,因为我的回复已发送。

或者长期运行的任务本身是否使...实例/线程/调用保持活动状态?还是一个 API 总是存在的?

    public async Task<ActionResult<int>> Get()
    {
        // second 0
        //... 
        var threadId = Thread.CurrentThread.ManagedThreadId;

        DoSomething60sAsync(); // #1 Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
        _ = DoSomething60sAsync(); // #2 No Warning

        Task.Run(DoSomething60sAsync); // #3 Same Warning as #1
        _ = Task.Run(DoSomething60sAsync); // # 4 No Warning

        return Ok(threadId); // second 2
    }

    private async Task DoSomething60sAsync()
    {
        for (int i = 0; i < 60; i++)
        {
            var threadId = Thread.CurrentThread.ManagedThreadId;

            Console.WriteLine(threadId + ": Second " + i);
            await Task.Delay(1000);
        }
    }

如您所见,我试图查看线程。我注意到它们都是后台线程。我还注意到 threadId 似乎完全随机。它甚至在那个 for 循环中发生变化。我读到 aspnetcore 线程很复杂。

鉴于无论如何它们都是后台线程,Task.Run在#3/#4 中使用似乎毫无意义。

我读到的解决这个问题的另一种方法是实现一个IHostedService和某种 TaskRunner-BackgroundQueue。https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-5.0&tabs=visual-studio

还有Hangfire。

我尝试了所有这些,它们似乎都有效。所以我想使用最简单的解决方案,但我担心只是“调用任务而不等待”会以某种方式丢失。这是一个有效的担忧吗?这会发生吗?

标签: c#asp.net-coreasp.net-core-webapi

解决方案


本质上,我只是想找到一种对传入请求执行某些操作的标准方式,这可能需要 5-300 秒,而客户端不必等待那么长时间才能得到响应。

这有几个名字。我称它为“基本分布式架构”,但“异步消息传递”也很常见。核心思想是你需要两件事:

  1. 持久队列。
  2. 一个后端进程。

在第 2 秒?5? 30?这...实例/线程/调用/执行环境刚刚关闭,因为它“完成”了。我“完成”了,因为我的回复已发送。或者长期运行的任务本身是否使...实例/线程/调用保持活动状态?还是一个 API 总是存在的?

失业当然是可能的。关机是正常的,当主机进程关闭时,工作可能会丢失。

鉴于无论如何它们都是后台线程,在#3/#4 中使用 Task.Run 似乎毫无意义。

在 ASP.NET Core 上,是的,这是真的。此外,丢弃(_ = )实际上只是告诉编译器“我知道我在做什么;不要给我警告”,因此您不会在这些行上收到警告,因为警告被静音了 - 代码是仍然一样危险(即,你仍然会失去工作)。

我读到的解决这个问题的另一种方法是实现 IHostedService 和某种 TaskRunner-BackgroundQueue。

为了防止丢失工作,您的队列必须是持久的(保存在磁盘上)。

还有Hangfire。

Hangfire(或IHostedService连接到持久队列)是实现异步消息传递的一种方式。由于我的博客中描述的原因,我倾向于在单独的进程中使用后台服务,但是 ASP.NET Core 进程中的后台服务也可以。


推荐阅读