Granos replicados
A veces, puede haber varias instancias del mismo grano activo, como cuando se opera un clúster múltiple y se usa OneInstancePerClusterAttribute. JournaledGrain está diseñado para admitir instancias replicadas con una fricción mínima. Se basa en proveedores de coherencia de registros para ejecutar los protocolos necesarios para asegurarse de que todas las instancias coinciden en la misma secuencia de eventos. En concreto, se encarga de los siguientes aspectos:
Versiones coherentes: todas las versiones del estado de grano (excepto las versiones provisionales) se basan en la misma secuencia global de eventos. En concreto, si dos instancias ven el mismo número de versión, ven el mismo estado.
Eventos de carreras: varias instancias pueden generar simultáneamente un evento. El proveedor de coherencia resuelve esta carrera y garantiza que todos están de acuerdo en la misma secuencia.
Notificaciones y reactividad: después de que se genere un evento en una instancia específica, el proveedor de coherencia no solo actualiza el almacenamiento, sino que también notifica a todas las demás instancias de grano.
Para obtener una explicación general de la coherencia, consulte nuestro TechReport y el documento de GSP (Protocolo de secuencia global).
Eventos condicionales
Los eventos de carreras pueden ser problemáticos si tienen un conflicto, es decir, no deben confirmarse por algún motivo. Por ejemplo, al retirar dinero de una cuenta bancaria, dos instancias pueden determinar de forma independiente que hay suficientes fondos para un retiro y emitir un evento de retiro. Pero la combinación de ambos eventos podría sobredibujarse. Para evitar esto, la API JournaledGrain
admite un método RaiseConditionalEvent.
bool success = await RaiseConditionalEvent(
new WithdrawalEvent() { /* ... */ });
Los eventos condicionales comprueban si la versión local coincide con la versión del almacenamiento. Si no es así, significa que la secuencia de eventos ha crecido mientras tanto, lo que significa que este evento ha perdido una carrera contra algún otro evento. En ese caso, el evento condicional no se anexa al registro y RaiseConditionalEvent devuelve un estado falso.
Esta es la analogía del uso de etiquetas electrónicas con actualizaciones de almacenamiento condicional y, del mismo modo, proporciona un mecanismo sencillo para evitar la confirmación de eventos en conflicto.
Es posible y razonable usar eventos condicionales e incondicionales para el mismo grano, como DepositEvent
y WithdrawalEvent
. Los depósitos no deben ser condicionales: aunque DepositEvent
pierda una carrera, no tiene que cancelarse, pero todavía se puede anexar a la secuencia global de eventos.
La espera de la tarea devuelta por RaiseConditionalEvent
es suficiente para confirmar el evento, es decir, no es necesario llamar también a ConfirmEvents
.
Sincronización explícita
A veces, es conveniente asegurarse de que un grano esté totalmente actualizado con la versión más reciente. Esto se puede conseguir llamando:
await RefreshNow();
Esto hace dos cosas:
- Confirma todos los eventos no confirmados.
- Carga la versión más reciente del almacenamiento.