Partilhar via


Confirmações imediatas e tardias

Neste artigo, você aprenderá as diferenças entre confirmações imediatas e tardias.

Confirmação imediata

Para muitos aplicativos, queremos garantir que os eventos sejam confirmados imediatamente, para que a versão persistente não fique atrás da versão atual na memória e não corremos o risco de perder o estado mais recente se o grão falhar. Podemos garantir isso seguindo estas regras:

  1. Confirme todas as RaiseEvent chamadas usando ConfirmEvents antes que o método grain retorne.
  2. Certifique-se de que as tarefas retornadas sejam RaiseConditionalEvent concluídas antes que o método grain retorne.
  3. Evite ReentrantAttribute ou AlwaysInterleaveAttribute atributos, para que apenas uma chamada de grão possa ser processada de cada vez.

Se seguirmos essas regras, isso significa que, depois que um evento é gerado, nenhum outro código de grão pode ser executado até que o evento tenha sido gravado no armazenamento. Portanto, é impossível observar inconsistências entre a versão na memória e a versão no armazenamento. Embora muitas vezes seja exatamente isso que queremos, também tem algumas desvantagens potenciais.

Desvantagens potenciais

  • Se a conexão com um cluster remoto ou armazenamento for temporariamente interrompida, o grão ficará indisponível: efetivamente, o grão não poderá executar nenhum código enquanto estiver preso esperando para confirmar os eventos, o que pode levar um tempo indefinido (o protocolo de consistência de log continua tentando novamente até que a conectividade de armazenamento seja restaurada).

  • Ao lidar com muitas atualizações para uma única instância de grão, confirmá-las uma de cada vez pode se tornar muito ineficiente, por exemplo, causando baixa taxa de transferência.

Confirmação atrasada

Para melhorar a disponibilidade e o rendimento nas situações mencionadas acima, os grãos podem optar por fazer um ou ambos os seguintes:

  • Permita que os métodos de grão levantem eventos sem esperar pela confirmação.
  • Permita a reentrância, para que o grão possa continuar processando novas chamadas, mesmo que as chamadas anteriores fiquem presas aguardando a confirmação.

Isso significa que o código grain pode ser executado enquanto alguns eventos ainda estão em processo de confirmação. A JournaledGrain<TGrainState,TEventBase> API tem algumas disposições específicas para dar aos desenvolvedores controle preciso sobre como lidar com eventos não confirmados que estão atualmente em voo.

A seguinte propriedade pode ser examinada para descobrir quais eventos não estão confirmados no momento:

IEnumerable<EventType> UnconfirmedEvents { get; }

Além disso, uma vez que o JournaledGrain<TGrainState,TEventBase>.State estado devolvido pela propriedade não inclui o efeito de eventos não confirmados, há uma propriedade alternativa

StateType TentativeState { get; }

Que retorna um estado "provisório", obtido de "Estado" aplicando todos os eventos não confirmados. O estado provisório é essencialmente um "melhor palpite" sobre o que provavelmente se tornará o próximo estado confirmado depois que todos os eventos não confirmados forem confirmados. No entanto, não há garantia de que isso realmente acontecerá, porque o grão pode falhar, ou porque os eventos podem correr contra outros eventos e perder, fazendo com que eles sejam cancelados (se forem condicionais) ou apareçam em uma posição posterior na sequência do que o previsto (se forem incondicionais).

Garantias de simultaneidade

Observe que Orleans as garantias de agendamento baseado em turnos (simultaneidade cooperativa) sempre se aplicam, mesmo quando se usa reentrância ou confirmação atrasada. Isso significa que, mesmo que vários métodos possam estar em andamento, apenas um pode estar sendo executado ativamente — todos os outros estão presos em uma espera, então nunca há corridas verdadeiras causadas por threads paralelos.

Note-se, em especial, que:

Essas garantias pressupõem que o código do usuário permanece dentro da prática recomendada em relação a tarefas e async/await (em particular, não usa tarefas de pool de threads, ou só as usa para código que não chama funcionalidade grain e que são devidamente aguardados).