Usługi robocze na platformie .NET

Istnieje wiele powodów tworzenia długotrwałych usług, takich jak:

  • Przetwarzanie danych intensywnie korzystających z procesora CPU.
  • Kolejkowanie elementów roboczych w tle.
  • Wykonywanie operacji opartej na czasie zgodnie z harmonogramem.

Przetwarzanie usługi w tle zwykle nie obejmuje interfejsu użytkownika, ale interfejsy użytkownika można tworzyć wokół nich. We wczesnych dniach pracy z programem .NET Framework deweloperzy systemu Windows mogą tworzyć usługi systemu Windows do tych celów. Teraz za pomocą platformy .NET możesz użyć BackgroundServiceelementu , który jest implementacją IHostedService, lub zaimplementować własne.

Platforma .NET nie jest już ograniczona do systemu Windows. Możesz tworzyć międzyplatformowe usługi w tle. Hostowane usługi są gotowe do rejestrowania, konfiguracji i wstrzykiwania zależności (DI). Są one częścią pakietu rozszerzeń bibliotek, co oznacza, że są one podstawowe dla wszystkich obciążeń platformy .NET, które współpracują z hostem ogólnym.

Ważne

Zainstalowanie zestawu .NET SDK powoduje również zainstalowanie Microsoft.NET.Sdk.Worker szablonu i procesu roboczego. Innymi słowy, po zainstalowaniu zestawu SDK platformy .NET można utworzyć nowy proces roboczy przy użyciu polecenia dotnet new worker . Jeśli używasz programu Visual Studio, szablon jest ukryty do momentu zainstalowania opcjonalnego obciążenia ASP.NET i tworzenia aplikacji internetowych.

Terminologia

Wiele terminów jest błędnie używanych synonimem. Ta sekcja definiuje niektóre z tych terminów, aby ich intencje w tym artykule były bardziej widoczne.

  • Usługa w tle: BackgroundService typ.
  • Hostowana usługa: implementacje IHostedServiceprogramu lub IHostedService samego siebie.
  • Długotrwała usługa: każda usługa, która działa w sposób ciągły.
  • Usługa systemu Windows: infrastruktura usługi systemu Windows, pierwotnie skoncentrowana na programie .NET Framework, ale teraz dostępna za pośrednictwem platformy .NET.
  • Usługa procesu roboczego: szablon usługi procesu roboczego.

Szablon usługi procesu roboczego

Szablon usługi procesu roboczego jest dostępny w interfejsie wiersza polecenia platformy .NET i programie Visual Studio. Aby uzyskać więcej informacji, zobacz interfejs wiersza polecenia platformy .NET, dotnet new worker — szablon. Szablon składa się z Program klasy i Worker .

using App.WorkerService;

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

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

Poprzednia Program klasa:

  • Tworzy element HostApplicationBuilder.
  • Wywołuje metodę AddHostedService rejestrowania Worker jako hostowanej usługi.
  • Tworzy element IHost z konstruktora.
  • host Wywołuje Run wystąpienie, które uruchamia aplikację.

Wartości domyślne szablonu

Szablon procesu roboczego domyślnie nie włącza odzyskiwania pamięci serwera ( GC), ponieważ istnieje wiele czynników, które odgrywają rolę w określaniu jego konieczności. Wszystkie scenariusze wymagające długotrwałych usług powinny uwzględniać wpływ na wydajność tego ustawienia domyślnego. Aby włączyć GC serwera, dodaj ServerGarbageCollection węzeł do pliku projektu:

<PropertyGroup>
    <ServerGarbageCollection>true</ServerGarbageCollection>
</PropertyGroup>

Kompromisy i zagadnienia

Włączony Disabled
Wydajne zarządzanie pamięcią: automatycznie odzyskuje nieużywaną pamięć, aby zapobiec wyciekom pamięci i zoptymalizować użycie zasobów. Zwiększona wydajność w czasie rzeczywistym: pozwala uniknąć potencjalnych przerw lub przerw spowodowanych przez odzyskiwanie pamięci w aplikacjach wrażliwych na opóźnienia.
Długoterminowa stabilność: pomaga utrzymać stabilną wydajność w długotrwałych usługach, zarządzając pamięcią w dłuższych okresach. Wydajność zasobów: może oszczędzać zasoby procesora CPU i pamięci w środowiskach ograniczonych zasobami.
Ograniczona konserwacja: minimalizuje potrzebę ręcznego zarządzania pamięcią, upraszczając konserwację. Ręczna kontrola pamięci: zapewnia precyzyjną kontrolę nad pamięcią dla wyspecjalizowanych aplikacji.
Przewidywalne zachowanie: przyczynia się do spójnego i przewidywalnego zachowania aplikacji. Nadaje się do krótkotrwałych procesów: minimalizuje nakład pracy związany z odzyskiwaniem pamięci w przypadku krótkotrwałych lub efemerycznych procesów.

Aby uzyskać więcej informacji na temat zagadnień dotyczących wydajności, zobacz Serwer GC. Aby uzyskać więcej informacji na temat konfigurowania GC serwera, zobacz Przykłady konfiguracji GC serwera.

Klasa procesu roboczego

Jeśli chodzi o Workerelement , szablon zapewnia prostą implementację.

namespace App.WorkerService;

public sealed class Worker(ILogger<Worker> logger) : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
            await Task.Delay(1_000, stoppingToken);
        }
    }
}

Poprzednia Worker klasa jest podklasą BackgroundService, która implementuje IHostedServiceelement . Element BackgroundService jest elementem abstract class i wymaga, aby podklasa zaimplementowała BackgroundService.ExecuteAsync(CancellationToken)element . W implementacji ExecuteAsync szablonu pętle raz na sekundę rejestrują bieżącą datę i godzinę do momentu zasygnalizowania anulowania procesu.

Plik projektu

Szablon Procesu roboczego opiera się na następującym pliku Sdkprojektu :

<Project Sdk="Microsoft.NET.Sdk.Worker">

Aby uzyskać więcej informacji, zobacz Zestawy SDK projektu .NET.

Pakiet NuGet

Aplikacja oparta na szablonie Procesu roboczego używa Microsoft.NET.Sdk.Worker zestawu SDK i zawiera jawne odwołanie do pakietu Microsoft.Extensions.Hosting .

Kontenery i możliwość dostosowywania do chmury

W przypadku większości nowoczesnych obciążeń platformy .NET kontenery są realną opcją. Podczas tworzenia długotrwałej usługi na podstawie szablonu Proces roboczy w programie Visual Studio możesz wyrazić zgodę na pomoc techniczną platformy Docker. Spowoduje to utworzenie pliku Dockerfile, który konteneryzuje aplikację .NET. Plik Dockerfile to zestaw instrukcji tworzenia obrazu. W przypadku aplikacji .NET plik Dockerfile zwykle znajduje się w katalogu głównym katalogu obok pliku rozwiązania.

# See https://aka.ms/containerfastmode to understand how Visual Studio uses this
# Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/runtime:8.0 AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["background-service/App.WorkerService.csproj", "background-service/"]
RUN dotnet restore "background-service/App.WorkerService.csproj"
COPY . .
WORKDIR "/src/background-service"
RUN dotnet build "App.WorkerService.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "App.WorkerService.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "App.WorkerService.dll"]

Powyższe kroki pliku Dockerfile obejmują:

  • Ustawianie obrazu podstawowego z mcr.microsoft.com/dotnet/runtime:8.0 jako aliasu base.
  • Zmiana katalogu roboczego na /app.
  • Ustawianie aliasu build z mcr.microsoft.com/dotnet/sdk:8.0 obrazu.
  • Zmiana katalogu roboczego na /src.
  • Kopiowanie zawartości i publikowanie aplikacji .NET:
  • Przekazywanie obrazu zestawu SDK platformy .NET z mcr.microsoft.com/dotnet/runtime:8.0 (aliasu base ).
  • Kopiowanie opublikowanych danych wyjściowych kompilacji z /publish.
  • Definiowanie punktu wejścia, który deleguje do elementu dotnet App.BackgroundService.dll.

Napiwek

McR to mcr.microsoft.com skrót od "Microsoft Container Registry" (Rejestr kontenerów firmy Microsoft) i jest katalogiem kontenerów syndyka firmy Microsoft z oficjalnego centrum Platformy Docker. Artykuł dotyczący wykazu kontenerów syndykates firmy Microsoft zawiera dodatkowe szczegóły.

W przypadku określania strategii wdrażania platformy Docker dla usługi procesu roboczego platformy .NET należy wziąć pod uwagę kilka zagadnień w pliku projektu:

<Project Sdk="Microsoft.NET.Sdk.Worker">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>true</ImplicitUsings>
    <RootNamespace>App.WorkerService</RootNamespace>
    <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
    <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
  </ItemGroup>
</Project>

W poprzednim pliku <DockerDefaultTargetOS> projektu element określa Linux jako element docelowy. Aby użyć kontenerów systemu Windows, użyj Windows zamiast tego. Microsoft.VisualStudio.Azure.Containers.Tools.Targets Pakiet NuGet jest automatycznie dodawany jako odwołanie do pakietu po wybraniu obsługi platformy Docker z szablonu.

Aby uzyskać więcej informacji na temat platformy Docker z platformą .NET, zobacz Samouczek: konteneryzowanie aplikacji .NET. Aby uzyskać więcej informacji na temat wdrażania na platformie Azure, zobacz Samouczek: wdrażanie usługi procesu roboczego na platformie Azure.

Ważne

Jeśli chcesz korzystać z wpisów tajnych użytkownika za pomocą szablonu Proces roboczy, musisz jawnie odwołać Microsoft.Extensions.Configuration.UserSecrets się do pakietu NuGet.

Rozszerzalność usługi hostowanej

Interfejs IHostedService definiuje dwie metody:

Te dwie metody służą jako metody cyklu życia — są one wywoływane odpowiednio podczas uruchamiania i zatrzymywania zdarzeń hosta.

Uwaga

Podczas zastępowania metod StartAsync lub StopAsync należy wywołać metodę i await metodę base klasy, aby upewnić się, że usługa zostanie uruchomiona i/lub zostanie prawidłowo zamknięta.

Ważne

Interfejs służy jako ograniczenie parametru typu ogólnego w AddHostedService<THostedService>(IServiceCollection) metodzie rozszerzenia, co oznacza, że dozwolone są tylko implementacje. Możesz korzystać z dostarczonej BackgroundService z podklasą lub całkowicie zaimplementować własną.

Uzupełnianie sygnału

W większości typowych scenariuszy nie trzeba jawnie sygnalizować ukończenia hostowanej usługi. Po uruchomieniu usług przez hosta są one przeznaczone do uruchamiania do momentu zatrzymania hosta. Jednak w niektórych scenariuszach może być konieczne zasygnaliowanie ukończenia całej aplikacji hosta po zakończeniu pracy usługi. Aby zasygnalizować ukończenie, rozważ następującą Worker klasę:

namespace App.SignalCompletionService;

public sealed class Worker(
    IHostApplicationLifetime hostApplicationLifetime,
    ILogger<Worker> logger) : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // TODO: implement single execution logic here.
        logger.LogInformation(
            "Worker running at: {Time}", DateTimeOffset.Now);

        await Task.Delay(1_000, stoppingToken);

        // When completed, the entire app host will stop.
        hostApplicationLifetime.StopApplication();
    }
}

W poprzednim kodzie ExecuteAsync metoda nie wykonuje pętli, a po zakończeniu wywołuje metodę IHostApplicationLifetime.StopApplication().

Ważne

Będzie to sygnalizować hostowi, że powinien zostać zatrzymany, a bez tego wywołania hosta StopApplication będzie nadal działać w nieskończoność.

Aby uzyskać więcej informacji, zobacz:

Zobacz też