Pular para o conteúdo

apps/data-patterns/database-per-service

082 · Dados & Persistência · ≈ 6 min de estudo

Database per Service

Cada microsserviço é o único dono do seu banco: nenhum outro serviço lê ou escreve as tabelas dele, e a integração acontece só por API. O schema evolui sem coordenar deploys, e cada serviço pode escolher o motor que lhe serve — aqui, PostgreSQL para Contas e MariaDB para Pagamentos, de propósito.

passos
6
arquivos
9
teste
1
tecnologias
6
Infraestrutura realTypeScriptBunElysiaPostgreSQLMariaDBDocker
Baixar cartão

Cenário

Banco digital com abertura de conta paga. O serviço de Contas abre a conta como pending; o serviço de Pagamentos recebe a tarifa de abertura, grava o pagamento no MariaDB dele e pede ao serviço de Contas que ative a conta. Pagamentos nunca toca o banco de Contas — nem para ler o status, nem para ativar.

Planta

Fluxo
8/8
Serviço de ContasServiço de PagamentosClienteAPI de Contas - ElysiaJSaccounts_db - PostgreSQLAPI de Pagamentos - ElysiaJSpayments_db - MariaDBReconciliador deativações pendentesPOST /accountsPOST /paymentsGET /accounts/:id e POST/accounts/:id/activation,com timeoutPOST/accounts/:id/activationproibido
8

8 passos — reproduza para seguir o fluxo

Como funciona

6 passos

Cada serviço dono do seu banco.

Esconde cada passo: lembre antes de tocar para revelar.

  1. 01

    Pagamentos consulta a conta pela API de Contas, sempre com timeout; conta desconhecida vira 404, serviço fora do ar vira 503 rápido

  2. 02

    Confere status pending e valor igual à tarifa; a chave única account_id no MariaDB barra a segunda tarifa, mesmo em corrida

  3. 03

    Grava o pagamento como activation_pending e só então chama a ativação — sem 2PC entre os dois bancos

  4. 04

    Ativação confirmada → pagamento completed (201); Contas sem resposta → pagamento fica pendente (202)

  5. 05

    O reconciliador repete as ativações pendentes; a ativação é idempotente (estado-alvo), então repetir é seguro

  6. 06

    account_id é referência por id, validada por API: nenhuma chave estrangeira atravessa a fronteira

Trade-offs

O que se ganha, o que se paga

3 vantagenscada ganho tem um preço3 custos

Vantagens

  • Schema de cada serviço evolui sozinho

  • Banco de um serviço cai sem levar o outro

  • Motor escolhido por serviço (PostgreSQL, MariaDB)

Custos

  • Sem JOIN entre serviços: consulta cruzada por API

  • Consistência eventual: estado pendente e reconciliação

  • Time precisa operar mais de um banco

apps/data-patterns/database-per-service

9 arquivos

./

  • docker-compose.ymlinfraPostgreSQL de Contas e MariaDB de Pagamentos

sql/

  • 01_accounts.sqlschemaSchema do banco de Contas
  • 01_payments.sqlschemaSchema do banco de Pagamentos, com chave única por conta

src/

  • api_accounts.tsServiço de Contas: abertura, consulta e ativação idempotente
  • api_payments.tsServiço de Pagamentos e reconciliador de ativações
  • client_accounts.tsCliente HTTP da API de Contas, com timeout
  • config_service.tsVariáveis de ambiente de cada serviço, validadas no boot
  • demo.tsdemoFluxo completo, tarifa duplicada e Contas fora do ar
  • api_payments.test.tstesteIsolamento, duplicidade, pendência com reconciliação e timeout contra os dois bancos reais

Executar · com Docker

  1. docker compose up -d --wait# sobe PostgreSQL · MariaDB
  2. bun install# dependências
  3. bun run demo# roda o cenário
  4. bun run test# integração contra o serviço real

Para subir os serviços separados: bun run accounts e bun run payments em terminais distintos.

Requisitos
BunDocker
Sobe junto
PostgreSQLMariaDB

Por que se relacionam

Teste rápido

Qual é o próximo passo depois de Database per Service?

Próximo projeto · Dados & PersistênciaShared Database (anti-padrão)
Esc

↑ ↓ navegarEnter abrir191 resultados