Visão geral do ciclo de vida do Orleans

Alguns comportamentos do Orleans são suficientemente complexos para precisarem de inicialização e desligamento ordenados. Alguns componentes com esses comportamentos incluem grãos, silos e clientes. Para resolver isso, foi introduzido um padrão de ciclo de vida de componente geral. Esse padrão consiste em um ciclo de vida observável, que é responsável por sinalizar estágios de inicialização e desligamento de um componente, e em observadores de ciclo de vida, responsáveis por executar operações de inicialização ou desligamento em estágios específicos.

Para obter mais informações, consulte Ciclo de vida de grãos e ciclo de vida de silos.

Ciclo de vida observável

Os componentes que precisam de inicialização e desligamento ordenados podem usar um ciclo de vida observável que permite que outros componentes observem o ciclo de vida e recebam uma notificação quando um estágio for atingido durante a inicialização ou desligamento.

public interface ILifecycleObservable
{
    IDisposable Subscribe(
        string observerName,
        int stage,
        ILifecycleObserver observer);
}

A chamada de assinatura registra um observador para notificação quando um estágio é atingido ao iniciar ou parar. O nome do observador é dado para fins de relatório. O estágio indica em que ponto na sequência de inicialização/desligamento o observador será notificado. Cada estágio do ciclo de vida é observável. Todos os observadores serão notificados quando o estágio for atingido ao iniciar e parar. Os estágios são iniciados em ordem crescente e interrompidos em ordem decrescente. O observador pode cancelar a assinatura descartando o descartável retornado.

Observador do ciclo de vida

Os componentes que precisam participar do ciclo de vida de outro componente precisam fornecer ganchos para seus comportamentos de inicialização e desligamento e assinar um estágio específico de um ciclo de vida observável.

public interface ILifecycleObserver
{
    Task OnStart(CancellationToken ct);
    Task OnStop(CancellationToken ct);
}

Tanto ILifecycleObserver.OnStart quanto ILifecycleObserver.OnStop são chamados quando o estágio ao qual se inscreveram é atingido durante a inicialização/desligamento.

Utilitários

Por praticidade, as funções auxiliares foram criadas para padrões comuns de uso do ciclo de vida.

Extensões

As funções de extensão existem para assinar o ciclo de vida observável, o que não exige que o componente de assinatura implemente ILifecycleObserver. Em vez disso, elas permitem que os componentes passem a função lambdas ou membros para serem chamados nos estágios assinados.

IDisposable Subscribe(
    this ILifecycleObservable observable,
    string observerName,
    int stage,
    Func<CancellationToken, Task> onStart,
    Func<CancellationToken, Task> onStop);

IDisposable Subscribe(
    this ILifecycleObservable observable,
    string observerName,
    int stage,
    Func<CancellationToken, Task> onStart);

Funções de extensão semelhantes permitem que argumentos de tipo genérico sejam usados no lugar do nome do observador.

IDisposable Subscribe<TObserver>(
    this ILifecycleObservable observable,
    int stage,
    Func<CancellationToken, Task> onStart,
    Func<CancellationToken, Task> onStop);

IDisposable Subscribe<TObserver>(
    this ILifecycleObservable observable,
    int stage,
    Func<CancellationToken, Task> onStart);

Participação no ciclo de vida

Alguns pontos de extensibilidade precisam de uma maneira de reconhecer quais componentes estão interessados em participar de um ciclo de vida. Uma interface de marcador de participante do ciclo de vida foi introduzida para essa finalidade. Mais detalhes sobre como isso é usado serão abordados ao explorar ciclos de vida de silos e grãos.

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

Exemplo

Veja abaixo um exemplo tirado de nossos testes de ciclo de vida de um componente que participa de um ciclo de vida observável em vários estágios do ciclo de vida.

enum TestStages
{
    Down,
    Initialize,
    Configure,
    Run,
};

class MultiStageObserver : ILifecycleParticipant<ILifecycleObservable>
{
    public Dictionary<TestStages,bool> Started { get; } = new();
    public Dictionary<TestStages, bool> Stopped { get; } = new();

    private Task OnStartStage(TestStages stage)
    {
        Started[stage] = true;

        return Task.CompletedTask;
    }

    private Task OnStopStage(TestStages stage)
    {
        Stopped[stage] = true;

        return Task.CompletedTask;
    }

    public void Participate(ILifecycleObservable lifecycle)
    {
        lifecycle.Subscribe<MultiStageObserver>(
            (int)TestStages.Down,
            _ => OnStartStage(TestStages.Down),
            _ => OnStopStage(TestStages.Down));

        lifecycle.Subscribe<MultiStageObserver>(
            (int)TestStages.Initialize,
            _ => OnStartStage(TestStages.Initialize),
            _ => OnStopStage(TestStages.Initialize));

        lifecycle.Subscribe<MultiStageObserver>(
            (int)TestStages.Configure,
            _ => OnStartStage(TestStages.Configure),
            _ => OnStopStage(TestStages.Configure));

        lifecycle.Subscribe<MultiStageObserver>(
            (int)TestStages.Run,
            _ => OnStartStage(TestStages.Run),
            _ => OnStopStage(TestStages.Run));
    }
}