Megosztás a következőn keresztül:


.NET Általános gazdagép

Ebben a cikkben megismerheti a Microsoft.Extensions.Hosting NuGet csomagban elérhető .NET Generic Host konfigurálásának és létrehozásának különböző mintáit. A .NET Általános gazdagép felelős az alkalmazások indítási és élettartam-kezeléséért. A Worker Service-sablonok létrehoznak egy .NET általános gazdagépet. HostApplicationBuilder Az általános gazdagép más típusú .NET-alkalmazásokkal, például konzolalkalmazásokkal is használható.

A gazdagép olyan objektum, amely az alkalmazás erőforrásait és élettartam-funkcióit foglalja magában, például:

  • Függőséginjektálás (DI)
  • Naplózás
  • Konfiguráció
  • Alkalmazásleállítás
  • IHostedService Megvalósítások

Amikor egy gazdagép elindul, IHostedService.StartAsync meghívja IHostedService a szolgáltatástároló üzemeltetett szolgáltatások gyűjteményében regisztrált összes implementációt. Egy feldolgozói szolgáltatásalkalmazásban minden IHostedService példányt tartalmazó BackgroundService implementációhoz meghívják a metódusokat BackgroundService.ExecuteAsync .

Az alkalmazás összes egymástól függő erőforrásának egy objektumba való belefogalmazásának fő oka az élettartam-kezelés: az alkalmazásindítás és a kecses leállítás vezérlése.

Gazdagép beállítása

A gazdagépet általában kód alapján konfigurálják, készítik és futtatják az Program osztályban. A Main módszer:

A .NET Worker Service-sablonok a következő kódot hozzák létre egy általános gazdagép létrehozásához:

using Example.WorkerService;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<Worker>();

IHost host = builder.Build();
host.Run();

A Worker Services szolgáltatással kapcsolatos további információkért lásd : Worker Services in .NET.

Gazdagépszerkesztő beállításai

A CreateApplicationBuilder módszer:

  • A tartalomgyökér beállítása a visszaadott GetCurrentDirectory()elérési útra.
  • Betölti a gazdagép konfigurációját a következőből:
    • A környezeti változók előtagja a következővel DOTNET_: .
    • Parancssori argumentumok.
  • Betölti az alkalmazáskonfigurációt a következőből:
    • appsettings.json.
    • appsettings. {Environment}.json.
    • Secret Manager, amikor az alkalmazás a Development környezetben fut.
    • Környezeti változók.
    • Parancssori argumentumok.
  • A következő naplózási szolgáltatókat adja hozzá:
    • Console
    • Hibakeresés
    • EventSource
    • EventLog (csak Windows rendszeren futtatva)
  • Engedélyezi a hatókör érvényesítését és a függőségek érvényesítését, ha a környezet .Development

Ez HostApplicationBuilder.Services egy Microsoft.Extensions.DependencyInjection.IServiceCollection példány. Ezek a szolgáltatások a függőséginjektálással a regisztrált szolgáltatások feloldásához használt szolgáltatások létrehozására IServiceProvider szolgálnak.

Keretrendszer által biztosított szolgáltatások

Hívás IHostBuilder.Build() esetén a HostApplicationBuilder.Build()rendszer automatikusan regisztrálja a következő szolgáltatásokat:

További forgatókönyvalapú gazdagépkészítők

Ha a weben készít vagy elosztott alkalmazást ír, előfordulhat, hogy másik gazdagépszerkesztőt kell használnia. Tekintse meg a további gazdagépszerkesztők alábbi listáját:

IHostApplicationLifetime

Injektálja a IHostApplicationLifetime szolgáltatást bármely osztályba az indítás utáni és a kecses leállítási feladatok kezeléséhez. A felületen három tulajdonság az alkalmazásindítási és az alkalmazásleállítási eseménykezelő metódusok regisztrálásához használt lemondási jogkivonatok. Az interfész egy metódust StopApplication() is tartalmaz.

Az alábbi példa egy IHostedService eseményregisztrációt regisztráló IHostApplicationLifetime és IHostedLifecycleService implementáció:

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace AppLifetime.Example;

public sealed class ExampleHostedService : IHostedService, IHostedLifecycleService
{
    private readonly ILogger _logger;

    public ExampleHostedService(
        ILogger<ExampleHostedService> logger,
        IHostApplicationLifetime appLifetime)
    {
        _logger = logger;

        appLifetime.ApplicationStarted.Register(OnStarted);
        appLifetime.ApplicationStopping.Register(OnStopping);
        appLifetime.ApplicationStopped.Register(OnStopped);
    }

    Task IHostedLifecycleService.StartingAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("1. StartingAsync has been called.");

        return Task.CompletedTask;
    }

    Task IHostedService.StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("2. StartAsync has been called.");

        return Task.CompletedTask;
    }

    Task IHostedLifecycleService.StartedAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("3. StartedAsync has been called.");

        return Task.CompletedTask;
    }

    private void OnStarted()
    {
        _logger.LogInformation("4. OnStarted has been called.");
    }

    private void OnStopping()
    {
        _logger.LogInformation("5. OnStopping has been called.");
    }

    Task IHostedLifecycleService.StoppingAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("6. StoppingAsync has been called.");

        return Task.CompletedTask;
    }

    Task IHostedService.StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("7. StopAsync has been called.");

        return Task.CompletedTask;
    }

    Task IHostedLifecycleService.StoppedAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("8. StoppedAsync has been called.");

        return Task.CompletedTask;
    }

    private void OnStopped()
    {
        _logger.LogInformation("9. OnStopped has been called.");
    }
}

A Worker Service sablon módosítható a ExampleHostedService megvalósítás hozzáadásához:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using AppLifetime.Example;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Services.AddHostedService<ExampleHostedService>();
using IHost host = builder.Build();

await host.RunAsync();

Az alkalmazás a következő mintakimenetet írja:

// Sample output:
//     info: AppLifetime.Example.ExampleHostedService[0]
//           1.StartingAsync has been called.
//     info: AppLifetime.Example.ExampleHostedService[0]
//           2.StartAsync has been called.
//     info: AppLifetime.Example.ExampleHostedService[0]
//           3.StartedAsync has been called.
//     info: AppLifetime.Example.ExampleHostedService[0]
//           4.OnStarted has been called.
//     info: Microsoft.Hosting.Lifetime[0]
//           Application started. Press Ctrl+C to shut down.
//     info: Microsoft.Hosting.Lifetime[0]
//           Hosting environment: Production
//     info: Microsoft.Hosting.Lifetime[0]
//           Content root path: ..\app-lifetime\bin\Debug\net8.0
//     info: AppLifetime.Example.ExampleHostedService[0]
//           5.OnStopping has been called.
//     info: Microsoft.Hosting.Lifetime[0]
//           Application is shutting down...
//     info: AppLifetime.Example.ExampleHostedService[0]
//           6.StoppingAsync has been called.
//     info: AppLifetime.Example.ExampleHostedService[0]
//           7.StopAsync has been called.
//     info: AppLifetime.Example.ExampleHostedService[0]
//           8.StoppedAsync has been called.
//     info: AppLifetime.Example.ExampleHostedService[0]
//           9.OnStopped has been called.

A kimenet az összes különböző életciklus-esemény sorrendjét jeleníti meg:

  1. IHostedLifecycleService.StartingAsync
  2. IHostedService.StartAsync
  3. IHostedLifecycleService.StartedAsync
  4. IHostApplicationLifetime.ApplicationStarted

Ha az alkalmazás leáll, például a Ctrl+C billentyűkombinációval, a következő események lépnek fel:

  1. IHostApplicationLifetime.ApplicationStopping
  2. IHostedLifecycleService.StoppingAsync
  3. IHostedService.StopAsync
  4. IHostedLifecycleService.StoppedAsync
  5. IHostApplicationLifetime.ApplicationStopped

IHostLifetime

Az IHostLifetime implementáció szabályozza, hogy mikor indul el a gazdagép, és mikor áll le. A rendszer az utolsó regisztrált implementációt használja. Microsoft.Extensions.Hosting.Internal.ConsoleLifetime az alapértelmezett IHostLifetime implementáció. A leállítás élettartam-mechanikájáról további információt a Gazdagép leállítása című témakörben talál.

Az IHostLifetime interfész egy metódust IHostLifetime.WaitForStartAsync tesz elérhetővé, amelynek elején IHost.StartAsync a program megvárja, amíg befejeződik, mielőtt folytatná. Ezzel késleltetheti az indítást, amíg egy külső esemény nem jelzi.

Emellett a IHostLifetime felület egy IHostLifetime.StopAsync metódust is elérhetővé tesz, amelyből IHost.StopAsync a rendszer azt jelzi, hogy a gazdagép leáll, és itt az ideje leállni.

IHostEnvironment

IHostEnvironment A szolgáltatás injektálása egy osztályba a következő beállításokkal kapcsolatos információk lekéréséhez:

A szolgáltatás emellett IHostEnvironment az alábbi bővítménymetódusok segítségével teszi lehetővé a környezet kiértékelését:

Gazdagép konfigurációja

A gazdagépkonfiguráció az IHostEnvironment implementáció tulajdonságainak konfigurálására szolgál.

A gazdagép konfigurációja elérhető a tulajdonságban IHostApplicationBuilder.Configuration , a környezet implementációja pedig a tulajdonságban IHostApplicationBuilder.Environment érhető el. A gazdagép konfigurálásához lépjen a Configuration tulajdonsághoz, és hívja meg az elérhető bővítménymetelyeket.

Gazdagépkonfiguráció hozzáadásához vegye figyelembe a következő példát:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Environment.ContentRootPath = Directory.GetCurrentDirectory();
builder.Configuration.AddJsonFile("hostsettings.json", optional: true);
builder.Configuration.AddEnvironmentVariables(prefix: "PREFIX_");
builder.Configuration.AddCommandLine(args);

using IHost host = builder.Build();

// Application code should start here.

await host.RunAsync();

A fenti kód a következőket végzi el:

  • A tartalomgyökér beállítása a visszaadott GetCurrentDirectory()elérési útra.
  • Betölti a gazdagép konfigurációját a következőből:
    • hostsettings.json.
    • A környezeti változók előtagja a következővel PREFIX_: .
    • Parancssori argumentumok.

Alkalmazáskonfiguráció

Az alkalmazáskonfiguráció egy hívással ConfigureAppConfigurationIHostApplicationBuilderjön létre. A nyilvánosIHostApplicationBuilder.Configuration tulajdonság lehetővé teszi a felhasználók számára a meglévő konfiguráció olvasását vagy módosítását az elérhető bővítménymetelyek használatával.

További információ: Konfiguráció a .NET-ben.

Gazdagép leállítása

Egy üzemeltetett folyamat többféleképpen is le van állítva. A üzemeltetett folyamatokat leggyakrabban a következő módokon lehet leállítani:

Az üzemeltetési kód nem felelős ezekért a forgatókönyvekért. A folyamat tulajdonosának ugyanúgy kell velük foglalkoznia, mint bármely más alkalmazásnak. A üzemeltetett szolgáltatásfolyamatok számos más módon is leállíthatók:

  • Ha ConsoleLifetime használják (UseConsoleLifetime), a következő jeleket figyeli, és megpróbálja kecsesen leállítani a gazdagépet.
    • SIGINT (vagy CTRL+C).
    • SIGQUIT (vagy CTRL+BREAK Windows rendszeren, CTRL+\ a Unixon).
    • SIGTERM (más alkalmazások, például docker stop).
  • Ha az alkalmazás hív Environment.Exit.

A beépített üzemeltetési logika kezeli ezeket a forgatókönyveket, különösen az osztályt ConsoleLifetime . ConsoleLifetime megpróbálja kezelni a SIGINT, SIGQUIT és SIGTERM "leállítás" jeleket, hogy lehetővé tegye az alkalmazás kecses kilépését.

A .NET 6 előtt nem volt mód arra, hogy a .NET-kód kecsesen kezelje a SIGTERM-et. A korlátozás ConsoleLifetime megkerüléséhez előfizetne a következőre System.AppDomain.ProcessExit: . Amikor ProcessExit a rendszer felemelte, jelezné a gazdagépnek, ConsoleLifetime hogy állítsa le és tiltsa le a ProcessExit szálat, várva, hogy a gazdagép leálljon.

A folyamat kilépési kezelője lehetővé tenné az alkalmazás törlési kódjának futtatását – például IHost.StopAsync a metódus utáni HostingAbstractionsHostExtensions.RunMain kódot.

Ezzel a megközelítéssel azonban más problémák is felmerültek, mert nem csak a SIGTERM volt az egyetlen módszer ProcessExit . A SIGTERM is elő van állítva az alkalmazáskód-hívások Environment.Exitsorán. Environment.Exit az alkalmazásmodell egy Microsoft.Extensions.Hosting folyamatának leállításának nem kecses módja. Az eseményt előhozzák ProcessExit , majd kilépnek a folyamatból. A metódus vége Main nem lesz végrehajtva. A háttér- és előtérszálak leállnak, a finally blokkok pedig nem lesznek végrehajtva.

Mivel ConsoleLifetime le van tiltvaProcessExit, amíg a gazdagép leáll, ez a viselkedés holtpontokhoz vezetett, és Environment.Exit a hívásra ProcessExitváró blokkokat is blokkolta. Emellett, mivel a SIGTERM-kezelés a folyamat kecses leállítását kísérelte meg, ConsoleLifetime a ExitCode felhasználónak átadott Environment.Exitkilépési kódot a következőre0állította be: .

A .NET 6-ban a POSIX-jelek támogatottak és kezelhetők. A ConsoleLifetime SIGTERM-et elegánsan kezeli, és a meghíváskor Environment.Exit a továbbiakban nem kerül bele.

Tipp.

A .NET 6+ ConsoleLifetime esetében már nincs logikája a forgatókönyv Environment.Exitkezeléséhez. Azok az alkalmazások, amelyek tisztítási logikát igényelnek Environment.Exit , előfizethetnek magukra ProcessExit . Az üzemeltetés ezekben a forgatókönyvekben többé nem próbálja meg kecsesen leállítani a gazdagépet.

Ha az alkalmazás üzemeltetést használ, és elegánsan le szeretné állítani a gazdagépet, ahelyett Environment.ExithívhatIHostApplicationLifetime.StopApplication.

Leállítási folyamat üzemeltetése

Az alábbi szekvenciadiagram bemutatja, hogyan kezelik a jeleket belsőleg az üzemeltetési kódban. A felhasználók többségének nem kell megértenie ezt a folyamatot. A mély megértést igénylő fejlesztők számára azonban egy jó vizualizáció segíthet az első lépésekben.

A gazdagép elindítása után, amikor egy felhasználó hívást indítRun, vagy WaitForShutdownegy kezelő regisztrálva lesz.IApplicationLifetime.ApplicationStopping A végrehajtás fel van függesztve WaitForShutdown, és az ApplicationStopping eseményre vár. A Main metódus nem tér vissza azonnal, és az alkalmazás addig fut, amíg RunWaitForShutdown vissza nem tér.

Amikor a rendszer jelet küld a folyamatnak, a következő sorrendet indítja el:

Leállítási sorozat diagramja.

  1. A vezérlő átfolyik ConsoleLifetime az esemény emeléséhez ApplicationLifetimeApplicationStopping . Ez jelzi WaitForShutdownAsync a végrehajtási kód letiltásának feloldását Main . Addig is a POSIX jelkezelő visszatér Cancel = true a POSIX-jel kezelése óta.
  2. A Main végrehajtási kód újra elkezdi a végrehajtást, és tájékoztatja a gazdagépet StopAsync(), amely leállítja az összes üzemeltetett szolgáltatást, és elindítja a többi leállított eseményt.
  3. WaitForShutdown Végül lépjen ki, és lehetővé teszi, hogy az alkalmazás megtisztítsa a kódot, és hogy a Main metódus kecsesen lépjen ki.

Gazdagép leállítása webkiszolgálói forgatókönyvekben

A Kestrelben számos más gyakori forgatókönyv is létezik a HTTP/1.1 és a HTTP/2 protokollok esetében, és hogyan konfigurálható különböző környezetekben egy terheléselosztóval a forgalom zökkenőmentes kiürítéséhez. Bár a webkiszolgáló konfigurációja meghaladja a jelen cikk hatókörét, további információt a ASP.NET Core Kestrel webkiszolgáló dokumentációjának konfigurálási lehetőségeiről talál.

Amikor a gazdagép leállítási jelet kap (például CTL+C vagy StopAsync), a rendszer jelzéssel ApplicationStoppingértesíti az alkalmazást. Elő kell fizetnie erre az eseményre, ha olyan hosszú ideig futó műveletekkel rendelkezik, amelyeknek kecsesen kell befejeződnie.

Ezután a gazdagép egy konfigurálható leállítási időtúllépéssel hívja IServer.StopAsync meg (alapértelmezett 30-at). A Kestrel (és a Http.Sys) zárja be a portkötéseket, és hagyja abba az új kapcsolatok elfogadását. Azt is közlik az aktuális kapcsolatokkal, hogy ne dolgozzanak fel új kéréseket. HTTP/2 és HTTP/3 esetén a rendszer előzetes GOAWAY üzenetet küld az ügyfélnek. HTTP/1.1 esetén leállítja a kapcsolati hurkot, mert a kérések feldolgozása sorrendben történik. Az IIS másképp viselkedik, ha elutasítja az új kéréseket egy 503-at tartalmazó állapotkóddal.

Az aktív kérések a leállítási időtúllépés befejezéséig vannak érvényben. Ha mind elkészültek az időtúllépés előtt, a kiszolgáló hamarabb visszaadja az irányítást a gazdagépnek. Ha az időtúllépés lejár, a függőben lévő kapcsolatok és kérések erőteljesen megszakadnak, ami hibákat okozhat a naplókban és az ügyfelekben.

A terheléselosztó szempontjai

A terheléselosztóval végzett munka során az ügyfelek zökkenőmentes átvitele új célhelyre az alábbi lépések végrehajtásával biztosítható:

  • Hozza létre az új példányt, és kezdje el a forgalom kiegyensúlyozását (skálázási célokra már lehet, hogy több példánya is van).
  • Tiltsa le vagy távolítsa el a régi példányt a terheléselosztó konfigurációjában, hogy ne kapjon új forgalmat.
  • Jelezzen a régi példánynak, hogy állítsa le.
  • Várja meg, amíg leereszti vagy időtúllépést végez.

Lásd még