Skip to content

Validate and update Models atomically

Let only one customer reserve a seat, even when requests arrive together.

Store whether the seat is reserved, and put the availability rule on the command that reserves it.

@Model
public record Seat(@EntityId SeatId seatId, boolean reserved) {}
public final class SeatId extends Id<Seat> {
public SeatId(String id) { super(id); }
}
public record CreateSeat(SeatId seatId) {
@Apply
Seat apply() { return new Seat(seatId, false); }
}
public record ReserveSeat(SeatId seatId) {
@AssertLegal
void check(Seat seat) {
if (seat.reserved()) throw new IllegalCommandException("Seat already reserved");
}
@Apply
Seat apply(Seat seat) { return new Seat(seatId, true); }
}

Send ReserveSeat through the command gateway. Fluxzero loads the seat, checks the rule and commits the change. If a competing change invalidates the read, the decision is retried against the newer state. A second reservation then meets the same “already reserved” rule.

Register the command types in your application; Spring discovers them in its scan. The fixture discovers them from the supplied commands.

var seatId = new SeatId("A1");
TestFixture.create()
.givenCommands(new CreateSeat(seatId), new ReserveSeat(seatId))
.whenCommand(new ReserveSeat(seatId))
.expectExceptionalResult(IllegalCommandException.class);

The check and the change belong to the same Model operation. Checking availability in a separate query before sending an unconditional update would leave a race between those two calls.

See Model updates for the annotations and atomic changes across Models when a booking must create a reservation as well.


© 2026 Fluxzero