architecture – Duplicate business logic check on Microservices Patterns

I’m reading now “Microservices Patterns” by Chris Richardson.
At chapter 5 “Designing business logic in a microservice architecture” the author present the Ticket aggregate and its methods.

While reading the “preparing” and “cancel” methods,
I have noticed that there is a state check of the ticket before the event is published.

When the service consume the events it has to verify the state again in a transaction manner using the database, which result a duplicated logic.

For example, if a Ticket is in a ACCEPTED state and both “cancel” and “prepare” methods are called, there would be a race that could only be handled using the db transaction.

I wanted to hear your thoughts on that and verify my understanding.

public List < TicketPreparationStartedEvent > preparing() {
    switch (state) {
        case ACCEPTED:
            this.state = TicketState.PREPARING;
            this.preparingTime = ZonedDateTime.now();
            return singletonList(new TicketPreparationStartedEvent());
        default:
            throw new UnsupportedStateTransitionException(state);
    }
}
public List < TicketDomainEvent > cancel() {
    switch (state) {
        case CREATED:
        case ACCEPTED:
            this.state = TicketState.CANCELLED;
            return singletonList(new TicketCancelled());
        case READY_FOR_PICKUP:
            throw new TicketCannotBeCancelledException();
        default:
            throw new UnsupportedStateTransitionException(state);
    }
}