2016-11-09 15 views
10

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.

Odpowiedz

9

Jeśli zamierzasz gościć.Aplikacje NET Core w Docker Polecam po prostu podążając za normalnym .NET Core Hosting API, gdzie dzwoni IWebHost.Run(), aby zablokować główny wątek i utrzymać przy życiu aplikację konsoli.

AppHostSelfBase jest po prostu numerem wrapper around .NET Core's hosting API, ale zamiast tego wywołuje niezablokowanie IWebHost.Start(). Aby uzyskać zachowanie IWebHost.Run(), powinieneś być w stanie ponownie użyć tego samego podejścia, co ManualResetEventSlim i Console.CancelKeyPress, że jest to łatwiejsze w użyciu Hosting API .NET Core i wywołanie Run() i tylko register your ServiceStack AppHost as a .NET Core module.

+0

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

+0

@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

+0

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

Powiązane problemy