Zastrzeżenie - to prawie to samo pytanie co docker container exits immediately even with Console.ReadLine() in a .net core console application - ale nie sądzę, że zaakceptowana odpowiedź na to pytanie jest zadowalająca.Kontroluj czas życia aplikacji konsoli .NET Core obsługiwanej w dockerze.
Co usiłuję osiągnąć
buduję aplikację konsoli (jest to usługa HTTP przy użyciu ServiceStack), który jest zbudowany z rdzenia .NET (dnxcore50 - jest to aplikacja konsoli, a nie ASP.NET podanie). Używam tej aplikacji w kontenerze dokowania na komputerze z systemem Linux. To zrobiłem, a usługa HTTP działa.
Mój problem
Mimo, że „mój serwis działa” - i to nie istnieje problem hosting usługi w pojemniku Döcker. Używam Console.ReadLine()
po uruchomieniu mojego detektora HTTP, ale ten kod nie blokuje się w kontenerze dokowanym, a kontener zakończy działanie natychmiast po uruchomieniu. Mogę uruchomić kontener dokera w trybie "interaktywnym", a usługa będzie tam siedzieć i słuchać, dopóki nie zabiję sesji interaktywnej, a następnie kontener zostanie zamknięty.
Kod Repo
Poniższy kod jest kompletny kod wystawianie do tworzenia mojej aplikacji .NET rdzenia konsoli servicestack testową.
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; }
}
Stary sposób rozwiązania tego problemu
Więc uprzednio obsługiwana za pomocą Mono (Mono miał poważne problemy z wydajnością - stąd przełącznik rdzenia NET) - sposób na naprawienie tego problemu było zastosowanie Mono.Posix
nasłuchiwać sygnału kill jak ten:
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();
}
}
teraz - rozumiem, że to nie będzie działać dla .NET rdzenia (oczywiście ponieważ Mono.Posix jest dla Mono!)
Rozwiązanie opisane w pokrewnym artykule (u góry tego wpisu) nie jest dla mnie przydatne - w środowisku produkcyjnym nie mogę oczekiwać, że kontener kontenera stanie się żywy, zapewniając sesję interaktywną, która będzie utrzymywać konsolę. ReadLine działa, ponieważ istnieje tam strumień STD-IN ...
Czy istnieje inny sposób na utrzymanie przy życiu kontenera dokowania (przy użyciu opcji(odłączona) podczas wywoływania docker run
) podczas hostowania aplikacji .NET Core?
Kod Refactor jako część Mythz sugestią
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();
}
}
}
ostateczne rozwiązanie!
dla potomności - rozwiązanie odejdę ze to kod, który można znaleźć tutaj (dzięki Mity dla wyjaśnienia): https://github.com/NetCoreApps/Hello/blob/master/src/SelfHost/Program.cs
Repo od stosownego kodu:
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);
});
}
W Nuget Mam zainstalowane Microsoft.NETCore.App, ServiceStack.Core i ServiceStack.Kestrel.
Użyłem kodu jako (myślę), że zasugerowałeś - wygląda na to, że działa zarówno w systemie Windows, jak i w moim Dockerze Linux ... aktualizacja jest do mojego pierwotnego pytania - na dole stanowisko. Co myślisz o rozwiązaniu? Czy zrozumiałem cię poprawnie? – Jay
@Jeśli to działa, jestem pewien, że jest w porządku, ale dlaczego nie skorzystać z zalecanego modelu hostingu .NET Core? Nie jest jasne, dlaczego chcesz zachować własną implementację. – mythz
Prawdopodobnie dlatego, że jeszcze tego nie rozumiem :) Jestem kompletnym noobem dla .NET core i naprawdę nie rozumiem, jak przykład tutaj: http://docs.servicestack.net/releases/v4.5.2.html # apphostbase-net-core-module będzie działać w systemie Linux; tj. co robi "UseIISIntegration()' w kontenerze Linux i jak ustawić port, którego chcę słuchać. Jestem tak przyzwyczajony do tworzenia prostych, samoobsługowych aplikacji konsolowych korzystających z ServiceStack - że chciałem czegoś, co działało tak samo jak wcześniej. Może potrzebuję trochę więcej czytać o rdzeniu .NET i modelu hostingu. – Jay