This PR focuses on Request-Response path applications as opposed to long-lived contexts as has previously been the focus. In the case of both new optimizations being adopted, users can see a reduction in 2/3rds of the read operations.
GetMachineReference(string machineId)
In request life-cycles a machine must be retrieved before a signal or input/payload can be sent, which requires I/O to ensure the machine exists. This has been mitigated with a new method on IStateEngine that does not require any I/O and is synchronous: GetMachineReference.
This also opens the door to more usage patterns where a machine reference would have been desired to store, but the I/O requirement meant designs had to instead hold a lower component and lazy initialize.
REstate is designed to minimize the possibility of stale writes for State as it's primary responsibility. The issue arises that each data-store handles concurrency differently, some with optimistic some pessimistic, and many have stale read semantics with eventual consistency. In the case of stale reads, this highly increases the chance of hitting a concurrency exception and needing to go through retry cycles. These differences has meant REstate has had to handle the worst case of each possible implementation previously. This is now being addressed with an optional interface IOptimisticallyConcurrentStateRepository<TState, TInput>that a Repository may implement. When implemented, REstate will send its recently loaded state to the repository so that the repository can avoid another read before making an update.
Current Implementations
EntityFrameworkCore
Planned Implementations
Redis (StackExchange v2 effort)
Why Should This Be In Core?
Required handling of new interface.
Benefits
Best case scenario of no contention reduces database calls by at least 1 and 3 in EntityFramework's case.
Possible Drawbacks
Elevated burden on caller to handle retries in hot paths.
This PR focuses on Request-Response path applications as opposed to long-lived contexts as has previously been the focus. In the case of both new optimizations being adopted, users can see a reduction in 2/3rds of the read operations.
GetMachineReference(string machineId)
In request life-cycles a machine must be retrieved before a signal or input/payload can be sent, which requires I/O to ensure the machine exists. This has been mitigated with a new method on IStateEngine that does not require any I/O and is synchronous:
GetMachineReference
.This also opens the door to more usage patterns where a machine reference would have been desired to store, but the I/O requirement meant designs had to instead hold a lower component and lazy initialize.
IOptimisticallyConcurrentStateRepository<TState, TInput>
REstate is designed to minimize the possibility of stale writes for State as it's primary responsibility. The issue arises that each data-store handles concurrency differently, some with optimistic some pessimistic, and many have stale read semantics with eventual consistency. In the case of stale reads, this highly increases the chance of hitting a concurrency exception and needing to go through retry cycles. These differences has meant REstate has had to handle the worst case of each possible implementation previously. This is now being addressed with an optional interface IOptimisticallyConcurrentStateRepository<TState, TInput>that a Repository may implement. When implemented, REstate will send its recently loaded state to the repository so that the repository can avoid another read before making an update.
Current Implementations
Planned Implementations
Why Should This Be In Core?
Required handling of new interface.
Benefits
Best case scenario of no contention reduces database calls by at least 1 and 3 in EntityFramework's case.
Possible Drawbacks
Elevated burden on caller to handle retries in hot paths.
Related Issues