PrepareKey
Key preparation interface for ensuring uniqueness constraints in EventSourcing architectures.
Unlike traditional databases that use UNIQUE KEY constraints, EventSourcing requires application-level uniqueness guarantees. PrepareKey provides a mechanism to "prepare" or reserve keys before they're actually used, ensuring atomicity and preventing race conditions.
Key features:
Atomic key preparation and rollback
TTL (Time-To-Live) support for temporary reservations
Reprepare operations for key changes
Transaction-like semantics with automatic rollback on failure
Common use cases:
Username/email uniqueness during user registration
Product SKU uniqueness
Resource identifier allocation
Preventing duplicate operations
Parameters
The type of value associated with prepared keys
Example usage for user registration:
@AggregateRoot
class User(private val state: UserState) {
@OnCommand
private fun onRegister(
register: Register,
passwordEncoder: PasswordEncoder,
usernamePrepare: PrepareKey<UsernameIndexValue>,
): Mono<Registered> {
val encodedPassword = passwordEncoder.encode(register.password)
return usernamePrepare.usingPrepare(
key = register.username,
value = UsernameIndexValue(
userId = state.id,
password = encodedPassword,
),
) {
require(it) {
"username[${register.username}] is already registered."
}
Registered(username = register.username, password = encodedPassword).toMono()
}
}
}Example usage for changing username:
@OnCommand
private fun onChangeUsername(
changeUsername: ChangeUsername,
usernamePrepare: PrepareKey<UsernameIndexValue>
): Mono<UsernameChanged> {
val usernameIndexValue = UsernameIndexValue(
userId = state.id,
password = state.password,
)
return usernamePrepare.reprepare(
oldKey = state.username,
oldValue = usernameIndexValue,
newKey = changeUsername.newUsername,
newValue = usernameIndexValue
).map {
require(it) {
"username[${changeUsername.newUsername}] is already registered."
}
UsernameChanged(username = changeUsername.newUsername)
}
}See also
for value wrapper with TTL support
for proxy-based implementation
Functions
Retrieves the full prepared value information including expiration status.
Reprepares a key with a new permanent value.
Reprepares a key with a new value that may have TTL.
Reprepares a key with a new value that never expires.
Reprepares by changing both key and value to new permanent values.
Reprepares by changing both key and value with optional TTL.
Executes an operation within a prepare context with permanent value.
Executes an operation within a prepare context with optional TTL.