Orleans silo 生命周期概述

Orleans silo 使用可观测的生命周期来有序启动和关闭 Orleans 系统以及应用程序层组件。 有关实现细节的详细信息,请参阅 Orleans 生命周期

阶段

Orleans silo 和群集客户端使用一组通用的服务生命周期阶段。

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

日志记录

由于控制反转,参与者加入生命周期而不是生命周期包含一些集中的初始化步骤集,因此在代码中并不始终明确启动/关闭顺序是什么。 为了帮助解决此问题,在 silo 启动之前添加了日志记录,以报告每个阶段参与的组件。 这些日志记录到 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."

Silo 生命周期参与

应用程序逻辑可以通过在 silo 的服务容器中注册参与服务来参与 silo 的生命周期。 服务必须注册为 ILifecycleParticipant<TLifecycleObservable>,其中 TISiloLifecycle

public interface ISiloLifecycle : ILifecycleObservable
{
}

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

当 silo 启动时,容器中的所有参与者 (ILifecycleParticipant<ISiloLifecycle>) 可以通过调用其 ILifecycleParticipant<TLifecycleObservable>.Participate 行为来参与生命周期。 在所有参与者都有机会参与后,silo 的可观测生命周期将按顺序启动所有阶段。

示例

随着 silo 生命周期的引入,不再需要过去允许应用程序开发人员在提供程序初始化阶段注入逻辑的启动提供程序,因为现在可以在任何 silo 启动阶段注入应用程序逻辑。 尽管如此,我们添加了一个“启动任务”结构,以帮助一直使用启动提供程序的开发人员过渡到新版本。 可以查看启动任务结构的示例来了解如何开发参与 silo 生命周期的组件。

启动任务只需继承自 ILifecycleParticipant<ISiloLifecycle> 并在应用程序逻辑中在指定的阶段订阅 silo 生命周期。

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(...) 调用中,应用程序逻辑在配置的阶段订阅了 silo 生命周期,并传递了应用程序回调而不是其初始化逻辑。 需要在给定阶段初始化的组件将提供其回调,但模式相同。 添加一个可以确保在配置的阶段调用应用程序挂钩的 StartupTask 后,我们需要确保 StartupTask 参与 silo 生命周期。

为此,我们只需将它注册到容器中。 我们使用 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;
}

在 silo 的服务容器中将 StartupTask 注册为标记接口 ILifecycleParticipant<ISiloLifecycle> 会向 silo 指明此组件需要参与 silo 生命周期。