I am currently building a microservice-based system to learn CQRS/ES, Docker, AMQP and all the other goodies that goes with it.
I have never asked a question online before as I am usually pretty good at finding answers to my queries by reading what that others have asked.
This time, I am stumped by what seems to be very simple.
Business documents such as invoices, purchase order, credit memos, etc. usually have an identifying number. (i.e. Invoice No.: 5707)
My question is how would I produce a sequential number for each of these types of documents in an event-sourced system?
I'm concerned about race conditions where an invoice number may inadvertently be duplicated or skipped. What is the best practice for this?
Thank you for your time.
EDIT: Here is what I tried:
I have an aggregate root (AR) called
Invoice that has an associated saga called
Invoice receives a command
Invoice AR processes this command and emits an event called
newInvoiceInitialization saga handles the
NewInvoiceWasCreated event and starts the saga to initialize the invoice AR. The
newInvoiceInitialization saga in-turn sends a
CheckoutNextInvoiceNumber command to another AR called
SequenceNumberGenerator with value objects:
SequenceNumberGenerator AR works with a saga called
SequenceNumberCheckoutSaga. These two will "check-out" the next
InvoiceNumber in the sequence and supply that to the
Invoice AR via a
newInvoiceInitialization saga receives the
SequenceNumberWasCheckoutOut event and sends the
InvoiceNumber to the
Invoice AR with a
Invoice AR completes the
newInvoiceInitialization saga successfully, it emits the event
InvoiceNumberWasAssignedToInvoice. This event triggers the
SequenceNumberCheckoutSaga to offers the command
FinalizeNumberCheckout to the
SequenceNumberGenerator AR which ends the
SequenceNumberCheckoutSaga and finalizes the usage of that number.
Invoice fails to accept the
InvoiceNumber or has other problems it sends the
InvoiceNumberAssignmentFailed event which causes the
SequenceNumberCheckoutSaga to command the
SequenceNumberGenerator AR with a
ResetNumberCheckout command to roll-back the checkout-out sequence number and ends the
This all just seems overly complicated to produce invoices with numbers that aren't missed or duplicated. I am probably missing something.