Partilhar via


Confirmações imediatas e tardias

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

Confirmação imediata

Para muitos aplicativos, você deseja garantir que os eventos sejam confirmados imediatamente. Isso evita que a versão persistente fique atrás da versão atual na memória e evita o risco de perder o estado mais recente se o grão falhar. Você pode 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 por RaiseConditionalEvent sejam concluídas antes que o método grain seja devolvido.
  3. Evite os atributos ReentrantAttribute ou AlwaysInterleaveAttribute, para que apenas uma chamada de grão seja processada de cada vez.

Se você seguir 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 armazenada. Embora isso muitas vezes seja exatamente o que você quer, 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 pode executar nenhum código enquanto espera para confirmar eventos, o que pode levar uma quantidade indefinida de tempo (o protocolo de consistência de log continua tentando novamente até que a conectividade de armazenamento seja restaurada).

  • Ao lidar com muitas atualizações de uma única instância de grain, confirmá-las uma de cada vez pode tornar-se muito ineficiente, potencialmente causando uma baixa taxa de processamento.

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 a entidade seja capaz de continuar a processar 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 sendo confirmados. A JournaledGrain<TGrainState,TEventBase> API tem disposições específicas que lhe dão um controlo preciso sobre como lidar com eventos não confirmados atualmente em voo.

Você pode examinar a seguinte propriedade para descobrir quais eventos não estão confirmados no momento:

IEnumerable<EventType> UnconfirmedEvents { get; }

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

StateType TentativeState { get; }

Essa propriedade retorna um estado "provisório", obtido de State pela aplicação de 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 ele realmente se tornará o estado confirmado. Isso ocorre porque o grão pode falhar, ou os eventos podem correr contra outros eventos e perder, fazendo com que eles sejam cancelados (se condicionais) ou apareçam mais tarde na sequência do que o previsto (se incondicional).

Garantias de concorrência

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, embora vários métodos possam estar em andamento, apenas um pode estar sendo executado ativamente — todos os outros estão presos em um await. Portanto, nunca há raças verdadeiras causadas por fios paralelos.

Note-se, em especial, que:

Essas garantias pressupõem que o seu código permaneça dentro das práticas recomendadas em relação a tarefas e async/await (em particular, não usa tarefas do pool de threads ou as usa apenas para código que não chama a funcionalidade grain e que é devidamente aguardado).