You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker容器中.NET Core 3.1应用优雅关机失效问题求助

问题分析

  1. StartAsync参数令牌误用:你注册的cancellationToken.Register()中的令牌是服务启动阶段的取消令牌,仅在启动过程被取消时触发,不会响应运行时的SIGTERM信号。
  2. ProcessExit事件时机错误:AppDomain.CurrentDomain.ProcessExit是进程退出前的最后触发事件,此时调用StopApplication()已经太晚,无法触发完整的优雅关机流程(包括StopAsync方法执行)。
  3. Shell脚本的进程管理缺陷:
    • 当前脚本仅等待第一个dotnet进程退出,第二个进程始终在后台运行,容器停止时会被直接发送SIGKILL强制终止,同时可能干扰第一个进程的关机流程。
    • 脚本在发送SIGTERM后立即等待第一个进程退出,若优雅关机需要时间,后续脚本退出可能导致容器提前终止,进程来不及完成StopAsync。
  4. UseSystemd()的不必要性:Docker容器中以shell脚本作为PID 1,而非systemd环境,UseSystemd()的信号处理逻辑无法正常工作,甚至会干扰.NET默认的信号监听。

修复步骤

1. 简化ShutdownService,依赖.NET默认信号处理

.NET的IHost默认会监听SIGTERM/SIGINT信号,并自动触发优雅关机流程(调用所有IHostedService的StopAsync),无需手动注册信号处理:

public class ShutdownService : IHostedService
{
    private readonly ILogger<ShutdownService> _logger;

    public ShutdownService(ILogger<ShutdownService> logger)
    {
        _logger = logger;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Shutdown service initialized.");
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Executing graceful shutdown.");
        // 在这里添加自定义优雅关机逻辑,比如等待正在处理的请求完成
        return Task.CompletedTask;
    }
}

2. 移除UseSystemd()调用

在主机构建器中删除UseSystemd(),适配Docker容器环境:

Host.CreateDefaultBuilder(args)
    .UseDefaultServiceProvider(o => o.ValidateScopes = false)
    .ConfigureServices((hostContext, services) =>
    {
        services.AddHostedService<ShutdownService>();
    });

3. 修复Shell脚本的信号传递与进程管理

确保所有后台进程都能收到SIGTERM,并等待所有进程完成优雅关机后再退出脚本:

#!/bin/bash

# 启动两个应用并记录PID
dotnet /App/myGracefulShutdownApp.dll &
PID1=$!
dotnet /App2/myOtherApp.dll &
PID2=$!

# 定义统一关机函数,给所有子进程发送SIGTERM并等待退出
shutdown() {
    echo "Received shutdown signal, initiating graceful stop..."
    kill -SIGTERM $PID1 $PID2
    wait $PID1
    wait $PID2
    echo "All processes exited gracefully."
}

# 捕获SIGTERM和SIGINT信号,触发关机函数
trap shutdown SIGTERM SIGINT

# 等待所有子进程,避免脚本提前退出
wait

4. 配置关机超时(可选)

给.NET主机设置关机超时,确保进程有足够时间完成优雅关机:

Host.CreateDefaultBuilder(args)
    .UseDefaultServiceProvider(o => o.ValidateScopes = false)
    .ConfigureServices((hostContext, services) =>
    {
        services.AddHostedService<ShutdownService>();
    })
    .ConfigureHostOptions(options =>
    {
        options.ShutdownTimeout = TimeSpan.FromSeconds(30);
    });

内容的提问来源于stack exchange,提问作者cmos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 18:50:23