Condividi tramite


Orleans Panoramica del ciclo di vita del silo

Orleans i silos usano un ciclo di vita osservabile per l'avvio ordinato e l'arresto dei Orleans sistemi e dei componenti del livello applicazione. Per altre informazioni sui dettagli dell'implementazione, vedere Orleans Ciclo di vita.

Fasi

Orleans i client silo e cluster usano un set comune di fasi del ciclo di vita del servizio:

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

Registrazione

A causa dell'inversione del controllo, in cui i partecipanti partecipano al ciclo di vita anziché il ciclo di vita con un set centralizzato di passaggi di inizializzazione, non è sempre chiaro dal codice che cos'è l'ordine di avvio/arresto. Per risolvere questo problema, Orleans aggiunge la registrazione prima dell'avvio del silo per segnalare quali componenti partecipano a ogni fase. Questi log vengono registrati a livello di log delle informazioni nel Orleans.Runtime.SiloLifecycleSubject logger. Per esempio:

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"

Inoltre, Orleans registra in modo analogo le informazioni sulla tempistica e sugli errori per ogni componente per fase. Per esempio:

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

Partecipazione al ciclo di vita del silo

La logica dell'applicazione può partecipare al ciclo di vita del silo registrando un servizio partecipante nel contenitore del servizio del silo. Registrare il servizio come ILifecycleParticipant<TLifecycleObservable>, dove T è ISiloLifecycle.

public interface ISiloLifecycle : ILifecycleObservable
{
}

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

All'avvio del silo, tutti i partecipanti (ILifecycleParticipant<ISiloLifecycle>) nel contenitore possono partecipare chiamando il loro comportamento ILifecycleParticipant<TLifecycleObservable>.Participate. Una volta che tutti hanno avuto l'opportunità di partecipare, il ciclo di vita osservabile del silo inizia tutte le fasi in ordine.

Esempio

Con l'introduzione del ciclo di vita del silo, i provider bootstrap, che in precedenza consentivano di inserire la logica nella fase di inizializzazione del provider, non sono più necessari. È ora possibile inserire la logica dell'applicazione in qualsiasi fase di avvio del silo. Tuttavia, abbiamo aggiunto un'interfaccia "attività di avvio" per facilitare la transizione per gli sviluppatori che utilizzavano i provider bootstrap. Come esempio di come è possibile sviluppare componenti che partecipano al ciclo di vita del silo, esaminiamo l'interfaccia del compito di avvio.

L'attività di avvio deve solo ereditare da ILifecycleParticipant<ISiloLifecycle> e associare la logica dell'applicazione al ciclo di vita del silo alla fase specificata.

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

Dall'implementazione precedente è possibile notare che nella Participate(...) chiamata si sottoscrive al ciclo di vita del silo alla fase configurata, passando il callback dell'applicazione anziché la sua logica di inizializzazione. I componenti che richiedono l'inizializzazione in una determinata fase forniscono il callback, ma il modello rimane invariato. Dopo aver verificato che l'hook dell'applicazione venga chiamato nella fase configurata con StartupTask, è necessario assicurarsi che StartupTask partecipi al ciclo di vita del silo.

A questo scopo, è sufficiente registrarlo nel contenitore. Eseguire questa operazione usando una funzione di estensione in 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;
}

Registrando il StartupTask nel contenitore del servizio del silo come interfaccia marcatrice ILifecycleParticipant<ISiloLifecycle>, si segnala al silo che questo componente deve partecipare al ciclo di vita del silo.