Orleans サイロのライフサイクルの概要

Orleans サイロでは、Orleans システムの順序付けされた起動とシャットダウン、アプリケーション層コンポーネントに監視可能なライフサイクルが使用されます。 実装の詳細については、Orleansのライフサイクルに関するページを参照してください。

ステージ

Orleans サイロおよびクラスター クライアントは、共通のサービス ライフサイクル ステージセットを使用します。

public static class ServiceLifecycleStage
{
    public const int First = int.MinValue;
    public const int RuntimeInitialize = 2_000;
    public const int RuntimeServices = 4_000;
    public const int RuntimeStorageServices = 6_000;
    public const int RuntimeGrainServices = 8_000;
    public const int ApplicationServices = 10_000;
    public const int BecomeActive = Active - 1;
    public const int Active = 20_000;
    public const int Last = int.MaxValue;
}

ログの記録

一元化された初期化ステップのセットを持つライフサイクルではなく、参加者がライフサイクルに参加する制御の逆転により、スタートアップまたはシャットダウンの順序がコードから必ずしも明らかになるとは限りません。 この問題に対処するために、サイロの起動前にログ記録が追加され、各ステージでどのコンポーネントが参加しているかが報告されます。 これらのログは、Orleans.Runtime.SiloLifecycleSubject ロガーの "情報" ログ レベルで記録されます。 次に例を示します。

Information, Orleans.Runtime.SiloLifecycleSubject, "Stage 2000: Orleans.Statistics.PerfCounterEnvironmentStatistics, Orleans.Runtime.InsideRuntimeClient, Orleans.Runtime.Silo"

Information, Orleans.Runtime.SiloLifecycleSubject, "Stage 4000: Orleans.Runtime.Silo"

Information, Orleans.Runtime.SiloLifecycleSubject, "Stage 10000: Orleans.Runtime.Versions.GrainVersionStore, Orleans.Storage.AzureTableGrainStorage-Default, Orleans.Storage.AzureTableGrainStorage-PubSubStore"

さらに、タイミングとエラーの情報は、各ステージでコンポーネントごとに同様にログに記録されます。 次に例を示します。

Information, Orleans.Runtime.SiloLifecycleSubject, "Lifecycle observer Orleans.Runtime.InsideRuntimeClient started in stage 2000 which took 33 Milliseconds."

Information, Orleans.Runtime.SiloLifecycleSubject, "Lifecycle observer Orleans.Statistics.PerfCounterEnvironmentStatistics started in stage 2000 which took 17 Milliseconds."

サイロのライフサイクルへの参加

アプリケーション ロジックは、サイロのサービス コンテナーに参加しているサービスを登録すると、サイロのライフサイクルに参加できます。 サービスは ILifecycleParticipant<TLifecycleObservable> として登録する必要があります。ここで T は、ISiloLifecycle です。

public interface ISiloLifecycle : ILifecycleObservable
{
}

public interface ILifecycleParticipant<TLifecycleObservable>
    where TLifecycleObservable : ILifecycleObservable
{
    void Participate(TLifecycleObservable lifecycle);
}

サイロが開始されると、コンテナー内のすべての参加者 (ILifecycleParticipant<ISiloLifecycle>) が、その ILifecycleParticipant<TLifecycleObservable>.Participate 動作を呼び出すと参加できるようになります。 すべてのユーザーが参加する機会を得た後、サイロの監視可能なライフサイクルにより、すべてのステージが順番に開始されます。

サイロ ライフサイクルの導入により、アプリケーション開発者がプロバイダーの初期化フェーズでロジックを挿入できるようにするために使用されるブートストラップ プロバイダーは不要になりました。これは、アプリケーション ロジックをサイロ スタートアップの任意の段階で挿入できるようになったためです。 それでも、ブートストラップ プロバイダーを使用していた開発者の移行を支援するために、"スタートアップ タスク" ファサードを追加しました。 サイロのライフサイクルに参加するコンポーネントを開発する方法の例として、スタートアップ タスクのファサードを見ていきます。

スタートアップ タスクは、ILifecycleParticipant<ISiloLifecycle> を継承し指定したステージで、アプリケーション ロジックを、サイロ ライフサイクルにサブスクライブするだけで済みます。

class StartupTask : ILifecycleParticipant<ISiloLifecycle>
{
    private readonly IServiceProvider _serviceProvider;
    private readonly Func<IServiceProvider, CancellationToken, Task> _startupTask;
    private readonly int _stage;

    public StartupTask(
        IServiceProvider serviceProvider,
        Func<IServiceProvider, CancellationToken, Task> startupTask,
        int stage)
    {
        _serviceProvider = serviceProvider;
        _startupTask = startupTask;
        _stage = stage;
    }

    public void Participate(ISiloLifecycle lifecycle)
    {
        lifecycle.Subscribe<StartupTask>(
            _stage,
            cancellation => _startupTask(_serviceProvider, cancellation));
    }
}

上記の実装から、Participate(...) 呼び出しでは、構成されたステージでサイロ ライフサイクルをサブスクライブし、初期化ロジックではなくアプリケーション コールバックを渡していることがわかります。 特定のステージで初期化する必要があるコンポーネントはコールバックを提供しますが、パターンは同じです。 構成されたステージでアプリケーションのフックが確実に呼び出されるようにする StartupTask が用意できたので、StartupTask がサイロ ライフサイクルに参加していることを確認する必要があります。

これを行うために必要なのは、コンテナーへの登録のみです。 これを行うには、ISiloHostBuilder の拡張関数を使用します。

public static ISiloHostBuilder AddStartupTask(
    this ISiloHostBuilder builder,
    Func<IServiceProvider, CancellationToken, Task> startupTask,
    int stage = ServiceLifecycleStage.Active)
{
    builder.ConfigureServices(services =>
        services.AddTransient<ILifecycleParticipant<ISiloLifecycle>>(
            serviceProvider =>
                new StartupTask(
                    serviceProvider, startupTask, stage)));

    return builder;
}

StartupTask をサイロのサービス コンテナーにマーカー インターフェイス ILifecycleParticipant<ISiloLifecycle> として登録すると、このコンポーネントがサイロのライフサイクルに参加する必要があることがサイロに通知されます。