☕🍃 SEQUENTIAL MICROSERVICES can quietly KILL your AVAILABILITY
☕🍃 SEQUENTIAL MICROSERVICES can quietly KILL your AVAILABILITY
Three reliable services can still create one less reliable request.
🔸 TLDR
If one request requires Inventory → Payment → Transport to ALL succeed, your availability is not 99.5%.
It is the product of their availabilities.
▪️ Inventory: 99.5%
▪️ Payment: 99.5%
▪️ Transport: 99.5%
0.995 × 0.995 × 0.995 = 0.985074875
👉 Effective availability ≈ 98.51%
Under a simple independent-failure model, three “highly available” services just turned a 0.5% unavailability rate into ~1.49%.
Over a 30-day month:
▪️ One service at 99.5% ≈ 3h36 unavailable
▪️ The 3-service synchronous chain ≈ 10h45
And correlated failures can make reality worse.

🔸 WHY?
Your endpoint succeeds only if EVERY mandatory dependency succeeds.
❗One timeout.
‼️One network issue.
❗‼️One overloaded service.
AND
💥 The whole business operation fails.
And simply calling the services in parallel does NOT fix availability if all 3 results are still mandatory.
It mainly reduces latency.
🔸 HOW TO MITIGATE IT?
▪️ Short timeouts→ fail quickly instead of exhausting threads.
▪️ Retries→ useful for transient failures, but bounded + backoff.
▪️ Circuit breakers→ stop hammering an unhealthy dependency.
▪️ Bulkhead→ isolate failures and protect your resources.
▪️ Fallbacks→ only when degraded data is business-acceptable.
▪️ Async workflows→ remove non-critical work from the synchronous path.
For example, payment may be mandatory NOW, while transport can happen asynchronously through an event/outbox:
paymentClient.pay(order);
outbox.save(
new TransportRequested(order.id())
);
return OrderStatus.ACCEPTED;🅰️🍃With Spring Cloud CircuitBreaker:
return circuitBreakerFactory .create("inventory") .run( () -> inventoryClient.check(id), ex -> cachedInventory(id) );
🅱️⛵For Jakarta-based applications, MicroProfile Fault Tolerance adds similar resilience patterns:
@Timeout(500) @Retry(maxRetries = 2) @CircuitBreaker @Fallback(fallbackMethod = "cachedInventory") Stock inventory(String id) { ... }
⚠️ But resilience patterns do not magically turn a failed required payment into a successful payment.
The architectural win is often:
👉 Make fewer remote calls mandatory for the synchronous success path.
🔸 TAKEAWAYS
▪️ Sequential dependency availability multiplies.
▪️ 99.5%³ ≈ 98.51%.
▪️ Parallelism helps latency, not “all must succeed” availability.
▪️ Retries/circuit breakers protect the system; they do not erase outages.
▪️ Async + outbox/event-driven workflows can shrink the critical path.
#Java #Spring #SpringBoot #JakartaEE #Microservices #DistributedSystems #SoftwareArchitecture #Resilience #Resilience4j #CloudNative
Go further with Java certification:
Java👇
Spring👇
SpringBook👇
JavaFullstackBook👇