Panoramica dei cicli di vita dei silos di Orleans

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

FASI

I client di silos e cluster Orleans 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, con i partecipanti che si uniscono al ciclo di vita, anziché essere il ciclo di vita ad avere un set centralizzato di passaggi di inizializzazione, l'ordine di avvio/arresto non è sempre evidente dal codice. Per risolvere questo problema, prima dell'avvio del silo è stata aggiunta una funzione di registrazione per segnalare quali componenti partecipano a ogni fase. I log vengono registrati a livello di Information sul logger Orleans.Runtime.SiloLifecycleSubject. Ad 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, le informazioni sulla tempistica e sugli errori vengono registrate in modo analogo per singolo componente in base alla fase. Ad 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 dei silos

La logica dell'applicazione può partecipare al ciclo di vita del silo registrando un servizio partecipante nel contenitore dei servizi del silo. Il servizio deve essere registrato come ILifecycleParticipant<TLifecycleObservable>, dove T è un'interfaccia 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 potranno partecipare chiamando il loro comportamento ILifecycleParticipant<TLifecycleObservable>.Participate. Quando tutti hanno avuto l'opportunità di partecipare, il ciclo di vita osservabile del silo avvierà tutte le fasi in modo ordinato.

Esempio

Con l'introduzione del ciclo di vita del silo, i provider bootstrap, che consentivano agli sviluppatori di applicazioni di inserire la logica nella fase di inizializzazione del provider, non sono più necessari, poiché la logica dell'applicazione può ora essere inserita in qualsiasi fase di avvio del silo. È stata tuttavia aggiunta una facciata di attività di avvio per facilitare la transizione per gli sviluppatori che usavano provider bootstrap. Come esempio del modo in cui possono essere sviluppati i componenti che partecipano al ciclo di vita del silo, esamineremo la facciata dell'attività di avvio.

L'attività di avvio deve ereditare solo da ILifecycleParticipant<ISiloLifecycle> e sottoscrivere la logica dell'applicazione al ciclo di vita del silo in corrispondenza della 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 chiamata a Participate(...), l'attività sottoscrive la logica dell'applicazione al ciclo di vita del silo nella fase configurata, passando il callback dell'applicazione anziché la propria logica di inizializzazione. I componenti che devono essere inizializzati in una determinata fase forniscono il proprio callback, ma il modello è lo stesso. Ora che è disponibile un oggetto StartupTask in grado di garantire che l'hook dell'applicazione venga chiamato nella fase configurata, è necessario assicurarsi che StartupTask partecipi al ciclo di vita del silo.

A tale scopo, è necessario registrarlo solo nel contenitore. Per eseguire questa operazione, si usa una funzione di estensione nell'interfaccia 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 l'oggetto StartupTask nel contenitore dei servizi del silo come interfaccia marcatore ILifecycleParticipant<ISiloLifecycle>, si segnala al silo che questo componente deve partecipare al suo ciclo di vita.