ivanslater wrote:
1- call OrderPlacedEvent and ProcessOrderPaid after transation completes. If some plugin tries to add notes or others DB transaction, they will get an "the underlying provider failed on open" because the transaction is closed.
--> The events should be called BEFORE the transaction is committed. Event handlers can then do changes that will be committed with the transaction. This way either the whole thing works or it doesn't. BUT, the operations in the event handlers should be only critical operations that need to be transactional with the core operation.
Only critical operations should be done in the transaction to minimize the chances of failure.
ivanslater wrote:
2- If you call them before transaction completes and some overrode method has untreated errors, all you order is gone and the problem is bigger.
--> The problem is only bigger if the operation that failed could be eventually consistent with the main operation, otherwise committing the order swallowing the error would be even worse.
The solution here is to separate transactional operations from eventually consistent operations. The way of doing it is:
1.- Execute all critical modifications in one local transaction (nop db)
2.- Within the local transaction, also store the event on a table (this is done in the transaction, so if the operation succeeds there'll be an event in the table, if the operation fails, the event won't be there)
3.- Later, using a task or other mechanism, check the events table to see if there are unprocessed events, process them and mark them as processed.
The main weakness here is that if there is a crash after processing the events and marking them as processed, it can happen that some operations are executed twice (things can be done to prevent this in most cases)