gpt4 book ai didi

c# - IHost.RunAsync() 永不返回

转载 作者:行者123 更新时间:2023-12-03 21:45:42 28 4
gpt4 key购买 nike

我正在构建一个将运行 BackgroundService 的 .NET Core 3.1 应用程序在 Docker 容器中。虽然我已经为 BackgroundService 实现了启动和关闭任务,并且在通过 SIGTERM 触发时服务肯定会关闭。 ,我发现 await host.RunAsync()调用永远不会完成 - 意味着我的 Main() 中的剩余代码块没有被执行。
我是否遗漏了什么或者我不应该期待 RunAsync()后台服务完成停止后调用返回控制?
(更新了我能想到的最简单的复制品......)

    using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace BackgroundServiceTest
{
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("Main: starting");
try
{
using var host = CreateHostBuilder(args).Build();

Console.WriteLine("Main: Waiting for RunAsync to complete");

await host.RunAsync();

Console.WriteLine("Main: RunAsync has completed");
}
finally
{
Console.WriteLine("Main: stopping");
}
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseConsoleLifetime()
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>();

// give the service 120 seconds to shut down gracefully before whacking it forcefully
services.Configure<HostOptions>(options => options.ShutdownTimeout = TimeSpan.FromSeconds(120));
});

}

class Worker : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
Console.WriteLine("Worker: ExecuteAsync called...");
try
{
while (!stoppingToken.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
Console.WriteLine("Worker: ExecuteAsync is still running...");
}
}
catch (OperationCanceledException) // will get thrown if TaskDelay() gets cancelled by stoppingToken
{
Console.WriteLine("Worker: OperationCanceledException caught...");
}
finally
{
Console.WriteLine("Worker: ExecuteAsync is terminating...");
}
}

public override Task StartAsync(CancellationToken cancellationToken)
{
Console.WriteLine("Worker: StartAsync called...");
return base.StartAsync(cancellationToken);
}

public override async Task StopAsync(CancellationToken cancellationToken)
{
Console.WriteLine("Worker: StopAsync called...");
await base.StopAsync(cancellationToken);
}

public override void Dispose()
{
Console.WriteLine("Worker: Dispose called...");
base.Dispose();
}
}
}
Dockerfile:
    #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/core/runtime:3.1-buster-slim AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["BackgroundServiceTest.csproj", "./"]
RUN dotnet restore "BackgroundServiceTest.csproj"
COPY . .
WORKDIR "/src/"
RUN dotnet build "BackgroundServiceTest.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "BackgroundServiceTest.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "BackgroundServiceTest.dll"]
docker -compose.yml:
    version: '3.4'

services:
backgroundservicetest:
image: ${DOCKER_REGISTRY-}backgroundservicetest
build:
context: .
dockerfile: Dockerfile
通过 docker-compose up --build 运行它然后在第二个窗口中运行 docker stop -t 90 backgroundservicetest_backgroundservicetest_1控制台输出显示 Worker 已关闭并被释放,但应用程序(显然)在 RunAsync() 之前终止。返回。
    Successfully built 3aa605d4798f
Successfully tagged backgroundservicetest:latest
Recreating backgroundservicetest_backgroundservicetest_1 ... done
Attaching to backgroundservicetest_backgroundservicetest_1
backgroundservicetest_1 | Main: starting
backgroundservicetest_1 | Main: Waiting for RunAsync to complete
backgroundservicetest_1 | Worker: StartAsync called...
backgroundservicetest_1 | Worker: ExecuteAsync called...
backgroundservicetest_1 | info: Microsoft.Hosting.Lifetime[0]
backgroundservicetest_1 | Application started. Press Ctrl+C to shut down.
backgroundservicetest_1 | info: Microsoft.Hosting.Lifetime[0]
backgroundservicetest_1 | Hosting environment: Production
backgroundservicetest_1 | info: Microsoft.Hosting.Lifetime[0]
backgroundservicetest_1 | Content root path: /app
backgroundservicetest_1 | Worker: ExecuteAsync is still running...
backgroundservicetest_1 | Worker: ExecuteAsync is still running...
backgroundservicetest_1 | info: Microsoft.Hosting.Lifetime[0]
backgroundservicetest_1 | Application is shutting down...
backgroundservicetest_1 | Worker: StopAsync called...
backgroundservicetest_1 | Worker: OperationCanceledException caught...
backgroundservicetest_1 | Worker: ExecuteAsync is terminating...
backgroundservicetest_1 | Worker: Dispose called...
backgroundservicetest_backgroundservicetest_1 exited with code 0

最佳答案

lengthy discussion on Github 之后,事实证明,一些小的重构解决了这个问题。简而言之,.RunAsync()阻塞直到主机完成并释放主机实例,这(显然)终止了应用程序。
通过更改代码调用.StartAsync()然后 await host.WaitForShutdownAsync() , 控制返回到 Main()正如预期的那样。最后一步是将主机配置在 finally 中。如图所示:

static async Task Main(string[] args)
{
Console.WriteLine("Main: starting");
IHost host = null;
try
{
host = CreateHostBuilder(args).Build();

Console.WriteLine("Main: Waiting for RunAsync to complete");
await host.StartAsync();

await host.WaitForShutdownAsync();

Console.WriteLine("Main: RunAsync has completed");
}
finally
{
Console.WriteLine("Main: stopping");

if (host is IAsyncDisposable d) await d.DisposeAsync();
}
}

关于c# - IHost.RunAsync() 永不返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64453235/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com