Database per Service

Table of Contents

This page defines the service architecture pattern Database per Service in the pattern language. Each service owns its data, and other services reach it only through the owner's operations. In ORE Studio components share one PostgreSQL instance, and still no service reads or writes another component's tables.

1. Also known as

  • Private data per service.

2. Context

Services are deployed separately and owned separately. The deployment happens to put their tables in one database.

3. Problem

Where does a service's data live, and how does another service read it?

4. Forces

  • A direct read is one query and no round trip.
  • A direct read skips the owner's authorisation and couples two schemas.
  • Owners must be free to change their tables.
  • Some reads span owners.

5. Solution

Each service owns its tables and serves them through operations on the bus. Any other service reads and writes them only through those operations, with the identity the call needs, and RLS applies as for any caller. A read that spans owners calls each owner, or a composer calls them and joins the answers.

pattern_database_per_service.png

Figure 1: Database per Service: ORE reads refdata's and analytics' documents through their operations, never their tables.

Source: [[./pattern_database_per_service.puml][pattern_database_per_service.puml]]. Regenerate with plantuml -tpng doc/knowledge/service_architecture_patterns/pattern_database_per_service.puml.

6. Failure handling

Concern What the pattern does
Errors An owner's refusal reaches the caller as an error, not as missing rows.
Timeouts Each owner call has its own timeout.
Retries Reads are safe to retry.
Idempotency Writes across owners need a Saga.
Observability Each owner logs the read it served.

7. Pitfalls

  • A shortcut through a shared connection. It compiles and returns rows, with no authorisation and no contract.
  • An owner linked as a library. Linking another component's core library is the same shortcut in code.
  • Many small calls. A per-row read across owners is slow; owners offer bulk reads.

8. Security

The owner's handler authorises every read, and RLS applies with the caller's tenant and party. A direct read would bypass both.

9. Resulting context

Benefits
Owners change their tables freely, and access control applies everywhere.
Liabilities
Round trips, and cross-owner reads need composition.

10. In ORE Studio

The curve construction, Bootstrapping a curve: from quotes to a published set, crosses refdata's recipe and market data's observations, each in its own store.

The surface construction, Constructing a volatility surface: from quotes to a published set, crosses refdata's recipe and conventions and market data's observations in the same way.

The market data path, a public fixing, a curve and a report, crosses four stores: market data, refdata, inbox and reporting, and each component owns its own.

11. Related patterns

12. Sources

  • Chris Richardson, Pattern: Database per service, microservices.io.
  • Sam Newman, Building Microservices, second edition, O'Reilly, 2021 — the case against sharing a database between services.

13. See also

Emacs 29.3 (Org mode 9.6.15)