Confirmações imediatas e atrasadas
Neste artigo, você aprenderá as diferenças entre confirmações imediatas e atrasadas.
Confirmação imediata
Para muitos aplicativos, queremos garantir que os eventos sejam confirmados imediatamente, para que a versão persistente não sofra atraso em relação à versão atual na memória e não corramos o risco de perder o estado mais recente se o grão falhar. Podemos garantir isso seguindo estas regras:
- Confirme todas as RaiseEvent chamadas que usam ConfirmEvents antes que o método de granularidade retorne.
- Certifique-se de que as tarefas retornadas por RaiseConditionalEvent sejam concluídas antes que o método de granulação retorne.
- Evite os atributos ReentrantAttribute ou AlwaysInterleaveAttribute, para que apenas uma chamada granular possa ser processada por vez.
Se seguirmos essas regras, isso significa que, depois que um evento for acionado, nenhum outro código de granularidade poderá 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 seja muitas vezes exatamente o que queremos, isso também tem algumas possíveis desvantagens.
Possíveis desvantagens
Se a conexão com um cluster ou armazenamento remoto for temporariamente interrompida, o grão ficará indisponível: efetivamente, o grão não poderá executar nenhum código enquanto estiver parado aguardando a confirmação dos eventos, o que pode levar um tempo indefinido (o protocolo continua tentando novamente até que a conectividade de armazenamento seja restaurada).
Ao manipular muitas atualizações para uma única instância de granularidade, 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 a taxa de transferência nas situações mencionadas acima, a granularidade pode optar por fazer um ou ambas das seguintes opções:
- Permitir que os métodos de granularidade gerem eventos sem aguardar a confirmação.
- Permitir a reentrada, para que a granularidade possa continuar processando novas chamadas, mesmo que as chamadas anteriores fiquem presas aguardando confirmação.
Isso significa que o código granular pode ser executado enquanto alguns eventos ainda estão em processo de confirmação. A API JournaledGrain<TGrainState,TEventBase> tem algumas cláusulas específicas para dar aos desenvolvedores controle preciso sobre como lidar com eventos não confirmados que estão atualmente em andamento.
A propriedade a seguir pode ser examinada para descobrir quais eventos não estão confirmados no momento:
IEnumerable<EventType> UnconfirmedEvents { get; }
Além disso, como o estado retornado pela propriedade JournaledGrain<TGrainState,TEventBase>.State não inclui o efeito de eventos não confirmados, existe 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 a granularidade pode falhar, ou porque os eventos podem competir contra outros eventos e perder, fazendo com que sejam cancelados (se forem condicionais) ou apareçam em uma posição posterior na sequência do que antecipadas (se forem incondicionais).
Garantias de simultaneidade
Observe que as garantias de agendamento baseado em turnos do Orleans (simultaneidade cooperativa) sempre se aplicam, mesmo ao usar reentrada 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 uma espera, portanto, nunca há corridas verdadeiras causadas por threads paralelos.
Em particular, observe que:
- As propriedadesState, TentativeStatee VersionUnconfirmedEvents podem ser alteradas durante a execução de um método.
- Mas essas mudanças só podem acontecer enquanto estiver preso em uma espera.
Essas garantias pressupõem que o código do usuário permaneça dentro da prática recomendada relativa a tarefas e async/await (em particular, não usa tarefas de pool de encadeamentos ou as usa apenas para código que não chama a funcionalidade granular e que são devidamente aguardado).