Partager via


Orleans Vue d’ensemble du cycle de vie du silo

Orleans les silos utilisent un cycle de vie observable pour le démarrage et l'arrêt ordonnés des systèmes et des composants de la couche applicative de Orleans. Pour plus d’informations sur les détails de l’implémentation, consultez Orleans cycle de vie.

Étapes

Orleans Les clients de silo et de cluster utilisent un ensemble commun d’étapes de cycle de vie des services :

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

Exploitation forestière

En raison de l’inversion du contrôle, où les participants rejoignent le cycle de vie plutôt que le cycle de vie ayant un ensemble centralisé d’étapes d’initialisation, il n’est pas toujours clair du code ce que l’ordre de démarrage/d’arrêt est. Pour résoudre ce problème, Orleans ajoute la journalisation avant le démarrage du silo pour signaler les composants qui participent à chaque étape. Ces logs sont enregistrés au niveau log Information sur le Orleans.Runtime.SiloLifecycleSubject logger. Par exemple:

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"

De même, Orleans journalise le minutage et les informations d’erreur pour chaque composant par étape. Par exemple:

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

Participation au cycle de vie du silo

Votre logique d’application peut participer au cycle de vie du silo en inscrivant un service participant dans le conteneur de service du silo. Inscrivez le service en tant que ILifecycleParticipant<TLifecycleObservable>, où T est ISiloLifecycle.

public interface ISiloLifecycle : ILifecycleObservable
{
}

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

Lorsque le silo démarre, tous les participants (ILifecycleParticipant<ISiloLifecycle>) du conteneur peuvent participer en ayant leur ILifecycleParticipant<TLifecycleObservable>.Participate comportement appelé. Une fois que tous ont eu l’occasion de participer, le cycle de vie observable du silo démarre toutes les étapes dans l’ordre.

Exemple :

Avec l’introduction du cycle de vie du silo, les fournisseurs bootstrap, qui vous ont précédemment permis d’injecter la logique à la phase d’initialisation du fournisseur, ne sont plus nécessaires. Vous pouvez désormais injecter une logique d’application à n’importe quel stade du démarrage de silo. Néanmoins, nous avons ajouté une façade de « tâche de démarrage » pour faciliter la transition pour les développeurs qui utilisaient les fournisseurs bootstrap. Par exemple, vous pouvez développer des composants qui participent au cycle de vie du silo, examinons la façade des tâches de démarrage.

La tâche de démarrage doit uniquement hériter de ILifecycleParticipant<ISiloLifecycle> et abonner la logique de l'application au cycle de vie du silo à l'étape spécifiée.

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

À partir de l’implémentation précédente, vous pouvez voir que dans l’appel Participate(...), il s’abonne au cycle de vie du silo à l’étape configurée, en transmettant le rappel de l'application plutôt que sa logique d’initialisation. Les composants nécessitant une initialisation à une étape donnée fournissent leur callback, mais le modèle reste le même. Maintenant que vous avez un StartupTask qui garantit que le hook de l'application est appelé à l'étape configurée, vous devez vous assurer que le StartupTask participe au cycle de vie du silo.

Pour cela, vous devez uniquement l’inscrire dans le conteneur. Procédez ainsi à l’aide d’une fonction d’extension sur 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;
}

En inscrivant le StartupTask dans le conteneur de service du silo en tant qu'interface de marqueur ILifecycleParticipant<ISiloLifecycle>, vous signalez au silo que ce composant doit participer au cycle de vie du silo.