[英]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()實現所使用的ManualResetEventSlim
和Console.CancelKeyPress
的相同方法,但個人而言,使用.NET Core的Hosting API和調用更容易Run()
並將ServiceStack AppHost注冊為.NET Core模塊 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.