Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Os grãos registados derivam de JournaledGrain<TGrainState,TEventBase>, com os seguintes parâmetros de tipo.
-
TGrainState
representa o estado do grão. Deve ser uma classe com um construtor padrão público. -
TEventBase
é um supertipo comum para todos os eventos que podem ser criados para este grão e pode ser qualquer classe ou interface.
Todos os objetos de estado e evento devem ser serializáveis porque os provedores de consistência de log podem precisar mantê-los e/ou enviá-los em mensagens de notificação.
Para grãos cujos eventos são POCOs (objetos C# antigos simples), você pode usar JournaledGrain<TGrainState> como uma abreviação para JournaledGrain<TGrainState,TEventBase>.
Leitura do estado do grão
Para ler o estado de grão atual e determinar seu número de versão, JournaledGrain
tem estas propriedades:
GrainState State { get; }
int Version { get; }
O número da versão sempre é igual ao número total de eventos confirmados, e o estado é o resultado da aplicação de todos os eventos confirmados ao estado inicial. O construtor padrão da classe determina o GrainState
estado inicial, que tem a versão 0 (porque nenhum evento foi aplicado a ele).
Importante: Seu aplicativo nunca deve modificar diretamente o objeto retornado pelo State
. Destina-se apenas à leitura. Quando seu aplicativo precisa modificar o estado, ele deve fazê-lo indiretamente, gerando eventos.
Gerar eventos
Gere eventos chamando a função RaiseEvent. Por exemplo, um grão que representa um bate-papo pode gerar um PostedEvent
para indicar que um usuário enviou uma postagem:
RaiseEvent(new PostedEvent()
{
Guid = guid,
User = user,
Text = text,
Timestamp = DateTime.UtcNow
});
Note que RaiseEvent
inicia uma gravação no armazenamento, mas não espera que esta seja concluída. Para muitos aplicativos, é importante aguardar a confirmação de que o evento foi persistente. Nesse caso, acompanhe sempre aguardando ConfirmEvents:
RaiseEvent(new DepositTransaction()
{
DepositAmount = amount,
Description = description
});
await ConfirmEvents();
Observe que, mesmo que você não ligue ConfirmEvents
explicitamente, os eventos acabam sendo confirmados automaticamente em segundo plano.
Métodos de transição de Estado
O tempo de execução atualiza o estado do grain automaticamente sempre que eventos são gerados. Seu aplicativo não precisa atualizar explicitamente o estado depois de gerar um evento. No entanto, seu aplicativo ainda precisa fornecer o código especificando como atualizar o estado em resposta a um evento. Você pode fazer isso de duas maneiras:
a) A GrainState
classe pode aplicar um ou mais Apply
métodos no StateType
. Normalmente, você cria várias sobrecargas e o tempo de execução escolhe a correspondência mais próxima para o tipo de tempo de execução do evento:
class GrainState
{
Apply(E1 @event)
{
// code that updates the state
}
Apply(E2 @event)
{
// code that updates the state
}
}
b) O grão pode substituir a função TransitionState
:
protected override void TransitionState(
State state, EventType @event)
{
// code that updates the state
}
Suponha que os métodos de transição não têm efeitos colaterais além de modificar o objeto de estado e devem ser determinísticos (caso contrário, os efeitos são imprevisíveis). Se o código de transição lançar uma exceção, Orleans captura-a e inclui-a Orleans em um aviso no log, emitido pelo provedor de consistência de log.
Quando exatamente o sistema chama os métodos de transição de estados depende do provedor de consistência de log escolhido e da sua configuração. Os aplicativos não devem depender de tempo específico, a menos que o provedor de consistência de log garanta explicitamente isso.
Alguns provedores, como o provedor de Orleans.EventSourcing.LogStorage consistência de log, reproduzem a sequência de eventos toda vez que o grão é carregado. Portanto, contanto que os objetos de evento ainda possam ser desserializados corretamente do armazenamento, você pode modificar radicalmente a GrainState
classe e os métodos de transição. No entanto, para outros provedores, como o provedor de consistência de log Orleans.EventSourcing.StateStorage, apenas o objeto GrainState
é persistido. Nesse caso, deve-se garantir que ele possa ser desserializado corretamente quando lido do espaço de armazenamento.
Acionar vários eventos
Você pode fazer várias chamadas para RaiseEvent
antes de ligar ConfirmEvents
:
RaiseEvent(e1);
RaiseEvent(e2);
await ConfirmEvents();
No entanto, isso provavelmente causa dois acessos sucessivos de armazenamento e incorre no risco de que o grão falhe depois de escrever apenas o primeiro evento. Assim, geralmente é melhor gerar vários eventos ao mesmo tempo usando:
RaiseEvents(IEnumerable<EventType> events)
Isso garante que a sequência dada de eventos seja gravada para armazenamento atomicamente. Observe que, como o número da versão sempre corresponde ao comprimento da sequência de eventos, gerar vários eventos aumenta o número da versão em mais de um de cada vez.
Recuperar a sequência de eventos
O seguinte método da classe base JournaledGrain
permite que seu aplicativo recupere um segmento especificado da sequência de todos os eventos confirmados:
Task<IReadOnlyList<EventType>> RetrieveConfirmedEvents(
int fromVersion,
int toVersion);
No entanto, nem todos os provedores de consistência de log oferecem suporte a esse método. Se não for suportado, ou se o segmento especificado da sequência não estiver mais disponível, um NotSupportedException será lançado.
Para recuperar todos os eventos até a última versão confirmada, ligue:
await RetrieveConfirmedEvents(0, Version);
Você só pode recuperar eventos confirmados: uma exceção será lançada se toVersion
for maior do que o valor atual da Version
propriedade.
Como os eventos confirmados nunca mudam, não há corridas com as quais se preocupar, mesmo com várias instâncias ou confirmação atrasada. No entanto, em tais situações, o valor da Version
propriedade pode ser maior no momento em que await
retoma do que quando RetrieveConfirmedEvents
foi chamado. Portanto, pode ser aconselhável salvar seu valor em uma variável. Consulte também a secção sobre Garantias de Concorrência.