通过.NET Core应用程序优雅地处理AWS ECS停止任务

时间:2018-12-14 17:16:36

标签: c# amazon-web-services .net-core amazon-ecs

我编写了一个.NET核心控制台应用程序,以作为任务在AWS ECS Fargate中运行。基本上,控制台应用程序会启动一个处理线程,然后只需保持运行状态(就像Kestrel Web主机一样)。

最初,我放入Console.ReadKey()认为它永远不会命中,并且应用程序将继续运行。嗯,这导致.NET异常...

Cannot read keys when either application does not have a console 
or when console input has been redirected. Try Console.Read.

因此我将ReadKey替换为Console.Read()。该应用程序的行为就像它还没有出现一样,一直在移动,并且在启动后立即退出。

通过研究,我发现了Console.CancelKeyPress事件。我实现了它,并且它在控制台应用程序将继续运行的事实中起作用。

ManualResetEvent _quitEvent = new ManualResetEvent(false);
Console.CancelKeyPress += (sender, eArgs) => {
                Console.WriteLine("Shutting down.");
                _quitEvent.Set();
                eArgs.Cancel = true;
            };
_quitEvent.WaitOne();

但是我想在发生这种情况时很好地处理应用程序的关闭。

通过其他研究,我发现当AWS ECS停止任务时,它不发送Ctrl-C(SIGINT),而是发送SIGTERM。 https://docs.aws.amazon.com/cli/latest/reference/ecs/stop-task.html

然后,我在.NET中实现我认为是SIGTERM的标准事件处理(见下文)。

AssemblyLoadContext.Default.Unloading += ctx =>
            {
                Console.WriteLine("Shutting down.");
                _quitEvent.Set();
            };
_quitEvent.WaitOne();

这可以在ECS中编译并正常运行。但是...我通过AWS ECS控制台单击“停止”按钮,它将停止任务并重新启动新任务。当我查看该已停止任务的日志时,没有关闭日志消息,也没有正常关闭的迹象,什么也没有。看来这只是被强行杀死。

我在这里错过了什么吗?我可以采取哪些其他措施来正常捕获AWS ECS中的停止任务以正常关闭该任务?

1 个答案:

答案 0 :(得分:0)

似乎与处理正常关机的.net代码有关。我刚刚在本地,docker和ECS Stop-Task中使用以下代码进行了测试。在所有地方,我都正常关机。我没有完整的代码,所以我创建了自己的示例。

using System;
using System.Runtime.Loader;
using System.Threading;

namespace consoleapp
{
    class Program
    {
        static void Main(string[] args)
        {
            var _quitEvent = new ManualResetEvent(false);
            AssemblyLoadContext.Default.Unloading += ctx =>
            {
                System.Console.WriteLine("Unloding fired");
                _quitEvent.Set();
            };
            System.Console.WriteLine("Waiting for signals");
            _quitEvent.WaitOne();
            System.Console.WriteLine("Received signal gracefully shutting down");
            Console.WriteLine("Hello World!");
        }
    }
}

如果您想自己尝试,请查阅完整的github repo参考。 https://github.com/imran9m/netconsoleapp.git

您应该在容器中看到的样本日志。

  

等待信号

     

解散触发

     

收到的信号正常关闭

     

Hello World!

注意-要在本地测试SIGTERM信号,您将需要在dotnet CLI上运行kill -SIGTERM {PID}而不是CTRL + C。