MicroservicePatterns.com
Design review

Check your own architecture

Describe your services, data stores and calls. Rule checks flag common anti-patterns as you type, each linked to the patterns that fix it. Then ask for an AI-assisted review of the trade-offs.

1. Describe the system

2. Services

3. Data stores

  • Used by
  • Used by

4. Calls and messages

5. Platform

Import or export as JSON

Diagram

Client → Orders (sync, timeout 10000)Client → Catalog (sync, timeout 5000)Orders → Payments (sync, timeout none)Orders → Inventory (sync, timeout 15000)Inventory → Warehouse (sync, timeout 3000)Warehouse → Shipping (sync, timeout 3000)Orders → Email (async)ClientClientOrdersOrdersCatalogCatalogPaymentsPaymentsInventoryInventoryEmailEmailWarehouseWarehouseShippingShippingMain databaseMain databasePayments databasePayments database

waits for reply message data access. Select a finding to highlight what it is about.

Rule checks

3 high · 10 medium · 2 low
  1. High

    Main database is written by 2 services

    Orders and Inventory both write to Main database. Nobody owns its schema, so any change needs every team, and one service's locks or load affect the others.

    What to do: Give Main database one owning service. Other services use its API, or keep their own copy from its events.

  2. High

    1 synchronous call has no timeout

    Orders → Payments. When the callee slows down, every waiting request holds a thread or connection in the caller until it runs out, and the slowdown spreads upstream.

    What to do: Set a connect and request timeout on every call, a little above the callee's normal p99 latency.

  3. High

    Data-changing calls are retried but are not idempotent

    Orders → Payments and Orders → Inventory change data and are retried. If the first attempt succeeded but the response was lost, the retry applies the change twice, such as a double charge.

    What to do: Send an idempotency key with each request and have the receiver ignore repeats, or stop retrying these calls.

  4. Medium

    Some services wait longer than their callers

    Client gives up on Orders after 10000 ms, but Orders waits 15000 ms for Inventory. Inventory gives up on Warehouse after 3000 ms, but Warehouse waits 3000 ms for Shipping. Downstream work continues after nobody is waiting for it.

    What to do: Make each inner timeout shorter than the one above it, or pass the remaining deadline down with the request.

  5. Medium

    Retries without backoff and jitter

    Orders → Payments and Inventory → Warehouse retry immediately. When the callee struggles, every caller retries at once and multiplies its load.

    What to do: Use exponential backoff with jitter and a small cap on attempts.

  6. Medium

    One request can become 9 calls at the bottom of a chain

    Along Client → Orders → Inventory → Warehouse → Shipping, each layer retries on its own, so a failure at the end is attempted up to 9 times, exactly when that service is least able to cope.

    What to do: Retry in one layer only, usually the one closest to the user, and add circuit breakers so retries stop when a dependency is clearly down.

  7. Medium

    A request crosses 4 synchronous hops

    Client → Orders → Inventory → Warehouse → Shipping. Latencies add up and availability multiplies down: every service in the chain must be up and fast for the request to succeed.

    What to do: Take steps that do not need an immediate answer out of the request path with messaging, or keep a local copy of the data the first service needs.

  8. Medium

    No circuit breaker in front of services that have their own dependencies

    Orders → Inventory and Inventory → Warehouse. When something further down fails, these callers keep sending traffic into it and wait on every request.

    What to do: Add a circuit breaker with a fallback, so callers fail fast while the dependency recovers.

  9. Medium

    Database writes and published messages can disagree

    Orders writes to a database and also publishes messages, without an outbox. If the process fails between the two, the data changes but the message is never sent, or the other way round.

    What to do: Write messages to an outbox table in the same transaction as the data, and publish them from there.

  10. Medium

    Orders changes data in 2 services in one request

    Orders updates Payments and Inventory synchronously. If a later call fails, the earlier changes stay in place and the services disagree.

    What to do: Model the operation as a saga with a compensating action for each step, coordinated by an orchestrator or by events.

  11. Medium

    Messages are not handled idempotently

    Orders → Email. Brokers deliver at least once, so these consumers will sometimes process the same message twice.

    What to do: Record each message ID in the same transaction as its effect and skip IDs you have already seen.

  12. Medium

    Clients call 2 services directly

    Clients know about Orders and Catalog. Authentication, TLS and rate limiting are repeated in each one, and you cannot reorganise services without breaking clients.

    What to do: Put an API gateway in front of the services, and consider a backend for frontend per client type.

  13. Medium

    No distributed tracing

    With 7 services, a slow or failed request is hard to follow from one service to the next.

    What to do: Propagate trace context on every call and message, and collect spans centrally.

  14. Low

    No dead letter queue for failing messages

    Orders → Email. A message that always fails will be retried forever or dropped, and can block the messages behind it.

    What to do: Move messages to a dead letter queue after a few failed attempts, alert on it, and make it possible to replay them.

  15. Low

    No health checks

    The platform cannot tell a stuck or still-starting instance from a healthy one, so it keeps sending it traffic.

    What to do: Expose separate liveness and readiness endpoints.

AI-assisted review

Sends this design, including the context text, to our review service for a written review of trade-offs. The rule checks above run in your browser. Do not include secrets or personal data.