簡體   English   中英

控制docker中托管的.NET Core控制台應用程序的生命周期

[英]Control lifetime of .NET Core console application hosted in docker

免責聲明 - 這與Docker容器即使在.net核心控制台應用程序中使用Console.ReadLine()立即退出也幾乎是同一個問題 - 但我不認為這個問題的接受答案是令人滿意的。

我想要實現的目標
我正在構建一個控制台應用程序(它是一個使用ServiceStack的HTTP服務),它是用.NET核心構建的(dnxcore50 - 這是一個控制台應用程序,而不是ASP.NET應用程序)。 我在Linux機器上的docker容器中運行此應用程序。 我已經完成了,HTTP服務正常工作。

我的問題
說過“我的服務有效” - 確實如此,在docker容器中托管服務存在問題。 我在啟動HTTP偵聽器后使用Console.ReadLine() ,但此代碼不會在docker容器中阻塞,並且容器將在啟動后立即退出。 我可以在“交互”模式下啟動docker容器,服務將在那里監聽,直到我終止交互式會話,然后容器將退出。

回購代碼
下面的代碼是一個完整的代碼清單,用於創建我的測試.NET核心Servicestack控制台應用程序。

public class Program
{
    public static void Main(string[] args)
    {
        new AppHost().Init().Start("http://*:8088/");
        Console.WriteLine("listening on port 8088");
        Console.ReadLine();

    }
}

public class AppHost : AppSelfHostBase
{
    // Initializes your AppHost Instance, with the Service Name and assembly containing the Services
    public AppHost() : base("My Test Service", typeof(MyTestService).GetAssembly()) { }

    // Configure your AppHost with the necessary configuration and dependencies your App needs
    public override void Configure(Container container)
    {

    }
}

public class MyTestService: Service
{
    public TestResponse Any(TestRequest request)
    {
        string message = string.Format("Hello {0}", request.Name);
        Console.WriteLine(message);
        return new TestResponse {Message = message};
    }

}

[Api("Test method")]
[Route("/test/{Name}", "GET", Summary = "Get Message", Notes = "Gets a message incorporating the passed in name")]
public class TestRequest : IReturn<TestResponse>
{
    [ApiMember(Name = "Name", Description = "Your Name", ParameterType = "path", DataType = "string")]
    public string Name { get; set; }
}

public class TestResponse 
{
    [ApiMember(Name = "Message", Description = "A Message", ParameterType = "path", DataType = "string")]
    public string Message { get; set; }
}

解決這個問題的舊方法
因此以前使用Mono托管(Mono有嚴重的性能問題 - 因此切換到.NET核心) - 修復此行為的方法是使用Mono.Posix監聽這樣的kill信號:

using Mono.Unix;
using Mono.Unix.Native;

...

static void Main(string[] args)
    {
        //Start your service here...

        // check if we're running on mono
        if (Type.GetType("Mono.Runtime") != null)
        {
            // on mono, processes will usually run as daemons - this allows you to listen
            // for termination signals (ctrl+c, shutdown, etc) and finalize correctly
            UnixSignal.WaitAny(new[] {
                new UnixSignal(Signum.SIGINT),
                new UnixSignal(Signum.SIGTERM),
                new UnixSignal(Signum.SIGQUIT),
                new UnixSignal(Signum.SIGHUP)
            });
        }
        else
        {
            Console.ReadLine();
        }
    }

現在 - 我明白這對.NET Core不起作用(顯然是因為Mono.Posix用於Mono!)

相關文章(本文頂部)中概述的解決方案對我沒用 - 在生產環境中,我不能期望通過確保它具有可保持Console.ReadLine的交互式會話來保持docker容器的活動狀態。工作,因為有一個STD-IN流...

在托管.NET Core應用程序時,是否有另一種方法可以使我的docker容器保持活動狀態(在調用docker run時使用-d (分離)選項)?

代碼重構是Mythz建議的一部分

 public static void Main(string[] args)
    {
        Run(new AppHost().Init(), "http://*:8088/");
    }

    public static void Run(ServiceStackHost host, params string[] uris)
    {
        AppSelfHostBase appSelfHostBase = (AppSelfHostBase)host;

        using (IWebHost webHost = appSelfHostBase.ConfigureHost(new WebHostBuilder(), uris).Build())
        {
            ManualResetEventSlim done = new ManualResetEventSlim(false);
            using (CancellationTokenSource cts = new CancellationTokenSource())
            {
                Action shutdown = () =>
                {
                    if (!cts.IsCancellationRequested)
                    {
                        Console.WriteLine("Application is shutting down...");
                        cts.Cancel();
                    }

                    done.Wait();
                };

                Console.CancelKeyPress += (sender, eventArgs) =>
                {
                    shutdown();
                    // Don't terminate the process immediately, wait for the Main thread to exit gracefully.
                    eventArgs.Cancel = true;
                };

                Console.WriteLine("Application started. Press Ctrl+C to shut down.");
                webHost.Run(cts.Token);
                done.Set();
            }
        }
    }

最終解決方案

對於后代 - 我已經使用的解決方案是可以在這里找到的代碼(感謝神話澄清): https//github.com/NetCoreApps/Hello/blob/master/src/SelfHost/Program.cs

相關代碼的回購:

public static void Main(string[] args)
    {
        var host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseStartup<Startup>()
            .UseUrls("http://*:8088/")
            .Build();

        host.Run();
    }
}

public class Startup
{
    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        // app.UseStaticFiles();

        app.UseServiceStack(new AppHost());

        app.Run(context =>
        {
            context.Response.Redirect("/metadata");
            return Task.FromResult(0);
        });
    }

在NuGet中,我安裝了Microsoft.NETCore.App,ServiceStack.Core和ServiceStack.Kestrel。

如果您要在Docker中托管.NET Core應用程序,我建議您按照正常的.NET Core Hosting API調用IWebHost.Run()來阻止主線程,並使控制台應用程序保持活動狀態。

AppHostSelfBase只是.NET Core托管API包裝,但是調用了非阻塞的IWebHost.Start() 要獲得IWebHost.Run()的行為,您應該能夠重用WebHost.Run()實現所使用ManualResetEventSlimConsole.CancelKeyPress的相同方法,但個人而言,使用.NET Core的Hosting API和調用更容易Run()並將ServiceStack AppHost注冊為.NET Core模塊

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM