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 在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"

此外, Orleans 按阶段记录每个组件的计时和错误信息。 例如:

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>,其中TISiloLifecycle

public interface ISiloLifecycle : ILifecycleObservable
{
}

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

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

示例:

随着孤岛生命周期的引入,不再需要那些在提供程序初始化阶段允许注入逻辑的启动提供程序。 现在可以在 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 参与到集群生命周期中。

为此,你只需要在容器中注册它。 使用 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>,可以向接收器发出信号,表明此组件需要参与接收器生命周期。