Usually the emit of messages should be delayed until the main transaction succeeded. Otherwise recipients will also receive messages in case of a rollback. To solve this problem, an outbox is used internally to defer the emit of messages until the success of the current transaction.
Using the persistent outbox, the to-be-emitted message is stored in a database table first. The same database transaction is used as for other operations, therefore transactional consistency is guaranteed.
The persistent outbox is globally enabled for all deferrable services (for example for cds.MessagingService and cds.AuditLogService). You can set the global outbox configuration, the defaults are:
maxAttempts (default 20): The number of unsuccessful emits until the message is ignored. It will still remain in the database table.
chunkSize (default 100): The number of messages which are read from the database table in one go.
storeLastError (default true): Specifies if error information of the last failed emit should be stored in the outbox table.
parallel (default true): Specifies if messages are sent in parallel (faster but the order isn't guaranteed).
Once the transaction succeeds, the messages are read from the database table and emitted. If an emit was successful, the respective message is deleted from the database table. If not, there will be retries after (exponentially growing) waiting times. After a maximum number of attempts, the message is ignored for processing and remains in the database table which therefore also acts as a dead letter queue. There is only one active message processor per service, tenant and app instance, hence there won't be duplicate emits except in the unlikely case of an app crash right after the emit and before the deletion of the message entry.
Some errors during the emit are identified as unrecoverable, for example in SAP Event Mesh if the used topic is forbidden. The respective message is then updated and the attempts field is set to maxAttempts to prevent further processing. Programming errors crash the server instance and must be fixed.
Your database model is automatically extended by the entity cds.outbox.Messages, as follows: