.NET の Worker サービス

実行時間の長いサービスを作成するには、次のようなさまざまな理由があります。

  • CPU 負荷の高いデータの処理。
  • バックグラウンドでの作業項目のキューイング。
  • スケジュールに基づく時間ベースの操作の実行。

バックグラウンド サービスの処理には、通常、ユーザー インターフェイス (UI) は含まれませんが、それを中心にして UI を作成することはできます。 .NET Framework の初期には、Windows 開発者がこのような理由で Windows サービスを作成することがありました。 現在の .NET では、BackgroundService を使用できます。これは、IHostedService の実装であるか、または独自に実装します。

.NET は Windows に限定されなくなりました。 クロスプラットフォームのバックグラウンド サービスを開発できます。 ホステッド サービスは、ログ記録、構成、依存関係の挿入 (DI) に対応しています。 これらはライブラリの拡張機能スイートの一部であり、汎用ホストで動作するすべての .NET ワークロードの基礎であることを意味します。

用語

多くの用語が誤って同義として使用されます。 このセクションでは、そのような用語のいくつかを定義し、意図を明確にします。

  • バックグラウンド サービス: 型のことです。
  • ホステッド サービス: の実装であるか、または IHostedService 自体を示します。
  • 実行時間の長いサービス: 継続的に実行されるサービス。
  • Windows サービス: Windows サービス インフラストラクチャは、当初は .NET Framework 中心でしたが、現在は .NET 経由でアクセスできます。
  • Worker サービス: Worker サービス テンプレートのことです。

ワーカー サービス テンプレート

Worker サービス テンプレートは、.NET CLI および Visual Studio で使用できます。 詳細については、.NET CLI の のテンプレートに関する記事を参照してください。 このテンプレートは、Program クラスと Worker クラスで構成されています。

using App.WorkerService;

IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddHostedService<Worker>();
    })
    .Build();

await host.RunAsync();

前の Program クラスは次のとおりです。

  • 既定の IHostBuilder を作成します。
  • ConfigureServices を呼び出して、AddHostedService でのホステッド サービスとして Worker を追加します。
  • ビルダーから IHost をビルドします。
  • host インスタンスで Run を呼び出します。アプリが実行されます。

ヒント

既定では、ワーカー サービス テンプレートによってサーバーのガベージ コレクション (GC) は有効にはなりません。 実行時間の長いサービスを必要とするすべてのシナリオで、この既定の状態のパフォーマンスへの影響を考慮する必要があります。 サーバーの GC を有効にするには、プロジェクト ファイルに ServerGarbageCollection ノードを追加します。

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

パフォーマンスに関する考慮事項の詳細については、「サーバーの GC」を参照してください。 サーバーの GC を構成する方法の詳細については、サーバーの GC の構成例を参照してください。

テンプレートの Program.cs ファイルは、最上位レベルのステートメントを使用して書き換えることができます。

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using App.WorkerService;

using IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices((hostContext, services) =>
    {
        services.AddHostedService<Worker>();
    })
    .Build();

await host.RunAsync();

これは、元のテンプレートと機能的に同等です。 C# 9.0 の機能の詳細については、「C# 9.0 の新機能」を参照してください。

Worker の場合と同様に、テンプレートでは単純な実装が提供されます。

namespace App.WorkerService
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;

        public Worker(ILogger<Worker> logger)
        {
            _logger = logger;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(1000, stoppingToken);
            }
        }
    }
}

上の Worker クラスは、IHostedService を実装する BackgroundService のサブクラスです。 BackgroundServiceabstract class であり、サブクラスで BackgroundService.ExecuteAsync(CancellationToken) を実装する必要があります。 テンプレートの実装では、ExecuteAsync が 1 秒に 1 回ループして、プロセスがキャンセルを通知されるまで、現在の日付と時刻をログに記録します。

プロジェクト ファイル

Worker サービス テンプレートは、次のプロジェクト ファイル Sdk に依存しています。

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

詳細については、「.NET プロジェクト SDK」を参照してください。

NuGet パッケージ

ワーカー サービス テンプレートに基づくアプリは Microsoft.NET.Sdk.Worker SDK を使用し、Microsoft.NET.Sdk.Worker パッケージへの明示的なパッケージ参照を含んでいます。

コンテナーとクラウドの適応可能性

最新の .NET ワークロードでは、コンテナーが実用的な選択肢です。 Visual Studio で Worker サービス テンプレートから長時間実行されるサービスを作成する場合は、Docker サポートにオプトインできます。 これにより、.NET アプリをコンテナー化する Dockerfile が作成されます。 Dockerfile は、イメージをビルドするための一連の手順です。 .NET アプリの場合、Dockerfile は通常、ソリューション ファイルの隣にあるディレクトリのルートに存在します。

# 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:5.0 AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:5.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"]

前の Dockerfile のステップには、次のものが含まれます。

  • mcr.microsoft.com/dotnet/runtime:6.0 の基本イメージのエイリアス base としての設定。
  • /app への作業ディレクトリの変更。
  • mcr.microsoft.com/dotnet/sdk:6.0 イメージからの build エイリアスの設定。
  • /src への作業ディレクトリの変更。
  • コンテンツのコピーと .NET アプリの発行。
    • このアプリは、dotnet publish コマンドを使用して発行されます。
  • mcr.microsoft.com/dotnet/runtime:6.0 の .NET SDK イメージの再階層化 (base エイリアス)。
  • 発行されたビルド出力の /publish からのコピー。
  • dotnet App.BackgroundService.dll に委任されるエントリ ポイントの定義。

ヒント

mcr.microsoft.com の MCR は "Microsoft Container Registry" を表し、公式の Docker Hub の Microsoft のシンジケート化されたコンテナー カタログです。 詳細については、Microsoft によるコンテナー カタログのシンジケート化に関する記事を参照してください。

.NET Worker サービスのデプロイ戦略として Docker をターゲットにする場合、プロジェクト ファイルで考慮することがいくつかあります。

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

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

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

前のプロジェクト ファイルの <DockerDefaultTargetOS> 要素では、ターゲットとして Linux が指定されています。 Windows コンテナーをターゲットにするには、代わりに Windows を使用します。 テンプレートから Docker サポートが選択されると、パッケージ参照として NuGet パッケージが自動的に追加されます。

.NET での Docker の詳細については、.NET アプリのコンテナー化のチュートリアルに関する記事を参照してください。 Azure へのデプロイの詳細については、Azure への Worker サービスのデプロイのチュートリアルに関する記事を参照してください。

重要

ワーカー サービス テンプレートを使用して "ユーザー シークレット" を活用する場合は、 NuGet パッケージを明示的に参照する必要があります。

ホステッド サービスの拡張性

IHostedService インターフェイスでは、2 つのメソッドが定義されています。

これら 2 つのメソッドは、"ライフサイクル" メソッドとして機能します。これらは、それぞれ、ホストの開始イベントと停止イベントの間に呼び出されます。

注意

StartAsync または StopAsync メソッドがオーバーライドされた場合、サービスが正常にシャットダウンされるように、base 基本クラス メソッドを呼び出す (および await する) 必要があります。

重要

このインターフェイスは、AddHostedService<THostedService>(IServiceCollection) 拡張メソッドでのジェネリック型パラメーターの制約として機能します。つまり、実装のみが許可されます。 サブクラスで提供されている BackgroundService を使用することも、独自のものを完全に実装することも自由にできます。

関連項目