Bagikan melalui


Layanan pekerja di .NET

Ada banyak alasan untuk membuat layanan jangka panjang seperti:

  • Memproses data intensif CPU.
  • Mengantrekan item kerja di latar belakang.
  • Melakukan operasi berbasis waktu sesuai jadwal.

Pemrosesan layanan latar belakang biasanya tidak melibatkan antarmuka pengguna (UI), tetapi UI dapat dibangun di sekitarnya. Pada hari-hari awal dengan .NET Framework, pengembang Windows dapat membuat Layanan Windows untuk tujuan ini. Sekarang dengan .NET, Anda dapat menggunakan BackgroundService, yang merupakan implementasi dari IHostedService, atau mengimplementasikan milik Anda sendiri.

Dengan .NET, Anda tidak lagi dibatasi untuk Windows. Anda dapat mengembangkan layanan latar belakang lintas platform. Layanan yang dihosting siap untuk pengelogan, konfigurasi, dan injeksi dependensi (DI). Mereka adalah bagian dari rangkaian ekstensi pustaka, yang berarti mereka mendasar untuk semua beban kerja .NET yang berfungsi dengan host generik.

Penting

Menginstal .NET SDK juga menginstal Microsoft.NET.Sdk.Worker templat dan pekerja. Dengan kata lain, setelah menginstal .NET SDK, Anda dapat membuat pekerja baru dengan menggunakan perintah dotnet new worker . Jika Anda menggunakan Visual Studio, templat disembunyikan hingga ASP.NET opsional dan beban kerja pengembangan web diinstal.

Terminologi

Banyak istilah yang keliru digunakan secara sinonim. Bagian ini mendefinisikan beberapa istilah ini untuk membuat niat mereka dalam artikel ini lebih jelas.

  • Layanan Latar Belakang: Jenisnya BackgroundService .
  • Layanan yang Dihosting: Implementasi IHostedService, atau itu IHostedService sendiri.
  • Layanan jangka panjang: Layanan apa pun yang berjalan terus menerus.
  • Layanan Windows: Infrastruktur Windows Service , awalnya .NET Framework-centric tetapi sekarang dapat diakses melalui .NET.
  • Layanan Pekerja: Templat Layanan Pekerja.

Templat Layanan Pekerja

Templat Layanan Pekerja tersedia di .NET CLI dan Visual Studio. Untuk informasi selengkapnya, lihat .NET CLI, dotnet new worker - templat. Templat terdiri dari kelas Program dan Worker .

using App.WorkerService;

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

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

Kelas sebelumnya Program :

Default templat

Templat Pekerja tidak mengaktifkan pengumpulan sampah server (GC) secara default, karena ada banyak faktor yang berperan dalam menentukan kebutuhannya. Semua skenario yang memerlukan layanan jangka panjang harus mempertimbangkan implikasi performa dari default ini. Untuk mengaktifkan server GC, tambahkan simpul ServerGarbageCollection ke file proyek:

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

Pertukaran dan pertimbangan

Aktif Nonaktif
Manajemen memori yang efisien: Secara otomatis mengklaim kembali memori yang tidak digunakan untuk mencegah kebocoran memori dan mengoptimalkan penggunaan sumber daya. Peningkatan performa real time: Menghindari potensi jeda atau gangguan yang disebabkan oleh pengumpulan sampah dalam aplikasi yang sensitif terhadap latensi.
Stabilitas jangka panjang: Membantu mempertahankan performa yang stabil dalam layanan jangka panjang dengan mengelola memori selama periode yang lama. Efisiensi sumber daya: Dapat menghemat sumber daya CPU dan memori di lingkungan yang dibatasi sumber daya.
Mengurangi pemeliharaan: Meminimalkan kebutuhan akan manajemen memori manual, menyederhanakan pemeliharaan. Kontrol memori manual: Menyediakan kontrol terperinci atas memori untuk aplikasi khusus.
Perilaku yang dapat diprediksi: Berkontribusi pada perilaku aplikasi yang konsisten dan dapat diprediksi. Cocok untuk proses berumur pendek: Meminimalkan overhead pengumpulan sampah untuk proses berumur pendek atau ephemeral.

Untuk informasi selengkapnya mengenai pertimbangan performa, lihat Server GC. Untuk informasi selengkapnya tentang mengonfigurasi GC server, lihat Contoh konfigurasi GC server.

Kelas pekerja

Adapun Worker, templat menyediakan implementasi sederhana.

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);
        }
    }
}

Kelas sebelumnya Worker adalah subkelas dari BackgroundService, yang mengimplementasikan IHostedService. BackgroundService adalah abstract class dan mengharuskan subkelas untuk mengimplementasikan BackgroundService.ExecuteAsync(CancellationToken). Dalam implementasi templat, perulangan ExecuteAsync sekali per detik, mencatat tanggal dan waktu saat ini hingga proses disinyalir dibatalkan.

File proyek

Templat Pekerja bergantung pada file Sdkproyek berikut:

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

Untuk informasi selengkapnya, lihat .NET project SDK.

Paket NuGet

Aplikasi berdasarkan templat Pekerja menggunakan Microsoft.NET.Sdk.Worker SDK dan memiliki referensi paket eksplisit ke paket Microsoft.Extensions.Hosting .

Kontainer dan kemampuan beradaptasi cloud

Dengan sebagian besar beban kerja .NET modern, kontainer adalah opsi yang layak. Saat membuat layanan jangka panjang dari templat Pekerja di Visual Studio, Anda dapat ikut serta dalam dukungan Docker. Melakukannya membuat Dockerfile yang mengontainerisasi aplikasi .NET Anda. Dockerfile adalah serangkaian instruksi untuk membangun sebuah gambar. Untuk aplikasi .NET, Dockerfile biasanya berada di akar direktori di samping file solusi.

# 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@sha256:e6b552fd7a0302e4db30661b16537f7efcdc0b67790a47dbf67a5e798582d3a5 AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:8.0@sha256:35792ea4ad1db051981f62b313f1be3b46b1f45cadbaa3c288cd0d3056eefb83 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"]

Langkah-langkah Dockerfile sebelumnya meliputi:

  • Mengatur gambar dasar dari mcr.microsoft.com/dotnet/runtime:8.0 sebagai alias base.
  • Mengubah direktori kerja ke /app.
  • build Mengatur alias dari mcr.microsoft.com/dotnet/sdk:8.0 gambar.
  • Mengubah direktori kerja menjadi /src.
  • Menyalin konten dan menerbitkan aplikasi .NET:
  • Relayering gambar .NET SDK dari mcr.microsoft.com/dotnet/runtime:8.0 ( base alias).
  • Menyalin output build yang diterbitkan dari /publish.
  • Menentukan titik masuk, yang mendelegasikan ke dotnet App.BackgroundService.dll.

Tip

MCR dalam mcr.microsoft.com adalah singkatan dari "Microsoft Container Registry", dan merupakan katalog kontainer sindikasi Microsoft dari hub Docker resmi. Artikel katalog kontainer sindikat Microsoft berisi detail tambahan.

Saat Anda menargetkan Docker sebagai strategi penyebaran untuk Layanan Pekerja .NET Anda, ada beberapa pertimbangan dalam file proyek:

<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="9.0.0" />
    <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.0" />
  </ItemGroup>
</Project>

Dalam file proyek sebelumnya, <DockerDefaultTargetOS> elemen menentukan Linux sebagai targetnya. Untuk menargetkan kontainer Windows, gunakan Windows sebagai gantinya. Paket Microsoft.VisualStudio.Azure.Containers.Tools.Targets NuGet secara otomatis ditambahkan sebagai referensi paket saat dukungan Docker dipilih dari templat.

Untuk informasi selengkapnya tentang Docker dengan .NET, lihat Tutorial: Membuat kontainer aplikasi .NET. Untuk informasi selengkapnya tentang penyebaran ke Azure, lihat Tutorial: Menyebarkan Layanan Pekerja ke Azure.

Penting

Jika Anda ingin memanfaatkan Rahasia Pengguna dengan templat Pekerja, Anda harus secara eksplisit mereferensikan Microsoft.Extensions.Configuration.UserSecrets paket NuGet.

Ekstensibilitas Layanan yang Dihosting

Antarmuka IHostedService mendefinisikan dua metode:

Kedua metode ini berfungsi sebagai metode siklus hidup - mereka dipanggil selama peristiwa mulai dan berhenti host masing-masing.

Catatan

Saat mengambil alih salah satu StartAsync atau StopAsync metode, Anda harus memanggil dan await base metode kelas untuk memastikan layanan dimulai dan/atau dimatikan dengan benar.

Penting

Antarmuka berfungsi sebagai batasan parameter jenis generik pada AddHostedService<THostedService>(IServiceCollection) metode ekstensi, yang berarti hanya implementasi yang diizinkan. Anda bebas menggunakan yang disediakan BackgroundService dengan subkelas, atau mengimplementasikan sendiri sepenuhnya.

Penyelesaian sinyal

Dalam skenario yang paling umum, Anda tidak perlu secara eksplisit memberi sinyal penyelesaian layanan yang dihosting. Ketika host memulai layanan, mereka dirancang untuk berjalan sampai host dihentikan. Namun, dalam beberapa skenario, Anda mungkin perlu memberi sinyal penyelesaian seluruh aplikasi host ketika layanan selesai. Untuk memberi sinyal penyelesaian, pertimbangkan kelas berikut Worker :

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();
    }
}

Dalam kode sebelumnya, ExecuteAsync metode tidak mengulang, dan ketika selesai, IHostApplicationLifetime.StopApplication()metode memanggil .

Penting

Ini akan memberi sinyal kepada host bahwa itu harus berhenti, dan tanpa panggilan ini ke StopApplication host akan terus berjalan tanpa batas waktu.

Untuk informasi selengkapnya, lihat:

Lihat juga