# Transactional Client

**In short:** A transactional client groups its message operations into one transaction. A sent message only enters the channel once the sender commits. The cost is slower performance in widely distributed systems.

## Explanation

A transactional client is a sender or receiver of messages that wraps its work in a transaction. A transaction is a group of steps that succeed together or not at all.

**Sending.** With a transactional sender, the message is not really in the channel until the sender commits. Until then, the send is provisional.

**The database-plus-message problem.** A service often must update its database and also send a message to a broker. Both must happen, or neither. The transactional outbox answers this problem. The service stores the outgoing message in its own database, in the same transaction as the business data. A separate relay process publishes the stored message later. (The article Message Channel explains channels.)

**Duplicates.** The relay might publish a message more than once. So the outbox gives at-least-once delivery, and receivers may see duplicates. The article Idempotent Receiver covers receivers that cope with repeats.

## Example

An order service saves a new order and must announce it to other systems. It writes the order and an "order created" message into its own database in one transaction. If the transaction fails, neither exists. If it commits, a relay later publishes the message. If the relay fails midway, it may publish the message again, so downstream systems must handle a repeat.

## Trade-offs

Transactional semantics can seriously degrade performance in widely distributed systems. This is why Amazon SQS uses visibility timeouts instead.

The outbox keeps the database change and the message together. In exchange, it accepts possible duplicate messages from the relay.

Transactional outbox: data and message are saved together, a relay publishes later.

```mermaid
flowchart LR
  A[Service] -->|one transaction| B[(Database: business data + outgoing message)]
  B --> C[Relay]
  C -->|may publish twice| D[Message channel]
```

## Checks

- If a service updates a database and sends a message, the document states how both are kept consistent, for example with an outbox.
- If a relay publishes outbox messages, the document states that duplicates are possible and how receivers handle them.
- If transactions span widely distributed systems, the document discusses the performance cost.

## Related

- [Idempotent Receiver](https://arc.fuet.ch/concepts/integration/idempotent-receiver.md)
- [Dead Letter Channel](https://arc.fuet.ch/concepts/integration/dead-letter-channel.md)
- [Message Channel](https://arc.fuet.ch/concepts/integration/message-channel.md)
- [Messaging](https://arc.fuet.ch/concepts/integration/messaging.md)
- [Request-Reply](https://arc.fuet.ch/concepts/integration/request-reply.md)
- [Retry](https://arc.fuet.ch/concepts/tactics/retry.md)

## Sources

- [Transactional Client - Enterprise Integration Patterns](https://www.enterpriseintegrationpatterns.com/patterns/messaging/TransactionalClient.html) — enterpriseintegrationpatterns.com, accessed 2026-11-09
- [Pattern: Transactional outbox](https://microservices.io/patterns/data/transactional-outbox.html) — microservices.io, accessed 2026-11-09
