Trait krill::commons::eventsourcing::WalSupport
source · pub trait WalSupport: Storable {
type Command: WalCommand;
type Change: WalChange;
type Error: Error + From<WalStoreError>;
// Required methods
fn revision(&self) -> u64;
fn apply(&mut self, set: WalSet<Self>);
fn process_command(
&self,
command: Self::Command
) -> Result<Vec<Self::Change>, Self::Error>;
}
Expand description
Implement this trait to get write-ahead logging support for a type.
We achieve write-ahead logging support by insisting that implementing types define the following:
- commands
Commands are used to send an intent to change the state. However, rather than changing the state, they return a result which can either be an error or a list of ‘events’.
- events
Events contain the data that can be applied to a type to change its state. We do this as a separate step, because this will allow us to replay events - from write-ahead logs - to get a stored snapshot to a current state.
The following caveats apply to this: – Events MUST NOT cause side-effects – Events MUST NOT return errors when applied – All state changes MUST use events
- errors
So that we can have type specific errors.
This is similar to how the [Aggregate
] trait works, and in fact
we re-use some its definitions here - such as [Event
] and [Command
].
But, there is a key difference which is that in this case there are no guarantees that all past events are kept - or rather they are very likely NOT kept. And we have no “init” event.
While there are similar concepts being used, the concerns here are
somewhat different.. we use this type to achieve atomicity and durability
by way of the WalStore
defined below, but we can keep things a bit
simpler here compared to the fully event-sourced [Aggregate
] types.
Required Associated Types§
type Command: WalCommand
type Change: WalChange
type Error: Error + From<WalStoreError>
Required Methods§
sourcefn apply(&mut self, set: WalSet<Self>)
fn apply(&mut self, set: WalSet<Self>)
Applies the event to this. This MUST not result in any errors, and this MUST be side-effect free. Applying the event just updates the internal data of the aggregate.
Note the event is moved. This is done because we want to avoid doing additional allocations where we can.
sourcefn process_command(
&self,
command: Self::Command
) -> Result<Vec<Self::Change>, Self::Error>
fn process_command( &self, command: Self::Command ) -> Result<Vec<Self::Change>, Self::Error>
Processes a command. I.e. validate the command, and return a list of events that will result in the desired new state, but do not apply these events here.
The command is moved, because we want to enable moving its data without reallocating.