Chaturmind
LearnDSASystem DesignDevOpsEngineering GrowthBlog
Start learning
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML
  • DevOps
  • Engineering Growth

Company

  • Blog
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

Built for engineers who want to go deep.


← Spring Boot REST API Development

Spring Boot Basics

  • What is Spring Boot?
  • Dependency Injection
  • Building REST Controllers

Validation & Error Handling

  • Bean Validation with @Valid
  • Global Exception Handling

Spring Framework Internals

  • IoC Container Fundamentals
  • Bean Lifecycle In Detail
  • Component Scanning & Configuration
  • Auto-Configuration Mechanism
  • Spring AOP
  • @Transactional Deep Dive

Microservices Architecture

  • Monolith to Microservices Decomposition
  • API Gateway
  • Service Discovery
  • Inter-Service Communication Choices
  • Event-Driven Architecture Patterns
  • Messaging Technology Choices

Resilience Patterns

  • Configuration Management
  • Circuit Breaker Pattern
  • Retry & Backoff Strategies
  • Bulkhead & Rate Limiting
  • Timeout Strategy
  • Why Microservices Fail

Distributed Data & Consistency Patterns

  • Two-Phase Commit
  • Saga Pattern
  • Outbox Pattern
  • Eventual Consistency Design
  • CQRS Basics
  • CAP Theorem

Observability & Operations

  • Centralized Logging
  • Distributed Tracing
  • Metrics & Monitoring
  • Alerting Strategy
  • Health Checks

Payment Systems

  • Payment — Requirements
  • Payment — Core Flow
  • Payment — Idempotency Implementation
  • Payment — Failure Handling & Reconciliation
  • Payment — Security

Order Management System

  • OMS — Requirements
  • OMS — State Machine Design
Chaturmind
← Spring Boot REST API Development

Spring Boot Basics

  • What is Spring Boot?
  • Dependency Injection
  • Building REST Controllers

Validation & Error Handling

  • Bean Validation with @Valid
  • Global Exception Handling

Spring Framework Internals

  • IoC Container Fundamentals
  • Bean Lifecycle In Detail
  • Component Scanning & Configuration
  • Auto-Configuration Mechanism
  • Spring AOP
  • @Transactional Deep Dive

Microservices Architecture

  • Monolith to Microservices Decomposition
  • API Gateway
  • Service Discovery
  • Inter-Service Communication Choices
  • Event-Driven Architecture Patterns
  • Messaging Technology Choices

Resilience Patterns

  • Configuration Management
  • Circuit Breaker Pattern
  • Retry & Backoff Strategies
  • Bulkhead & Rate Limiting
  • Timeout Strategy
  • Why Microservices Fail

Distributed Data & Consistency Patterns

  • Two-Phase Commit
  • Saga Pattern
  • Outbox Pattern
  • Eventual Consistency Design
  • CQRS Basics
  • CAP Theorem

Observability & Operations

  • Centralized Logging
  • Distributed Tracing
  • Metrics & Monitoring
  • Alerting Strategy
  • Health Checks

Payment Systems

  • Payment — Requirements
  • Payment — Core Flow
  • Payment — Idempotency Implementation
  • Payment — Failure Handling & Reconciliation
  • Payment — Security

Order Management System

  • OMS — Requirements
  • OMS — State Machine Design
HomeLearnSpring BootSpring Boot REST API DevelopmentMicroservices Architecture
✓ FreeAdvanced· 10 min read

Inter-Service Communication Choices

REST vs gRPC vs async messaging, request-response vs fire-and-forget vs pub-sub, Feign vs RestTemplate vs WebClient, REST vs SOAP, and Reactor's Mono/Flux with backpressure.

Published September 23, 2026


Inter-Service Communication Choices

Synchronous REST

Simplest to build, test, and reason about — a caller makes an HTTP request and gets a response inline. The direct cost: the caller's own response time is coupled to the callee's availability and latency — if the downstream service is slow or down, the caller is blocked (or fails) waiting on it, and that coupling can cascade across a chain of synchronous calls.

gRPC

A binary protocol (Protocol Buffers over HTTP/2) with strongly-typed contracts defined in .proto files — client and server code is generated from the same contract, eliminating an entire class of "the client's assumed shape doesn't match the server's actual response" bugs that loosely-typed JSON-over-REST is prone to. Binary encoding plus HTTP/2 multiplexing gives meaningfully lower latency and bandwidth than REST/JSON for high-throughput internal service-to-service traffic — the tradeoff is less human-readability (you can't just curl and eyeball a response the way you can with JSON) and a steeper adoption cost (code generation tooling, less universal client support than plain HTTP/JSON).

Asynchronous messaging

[Producer] → publishes an event → [Message Broker: Kafka/RabbitMQ] → [Consumer(s)] process whenever ready

Decouples timing entirely — the producer doesn't wait for (or even know about) the consumer's processing, and a temporarily slow or down consumer doesn't block the producer at all, just delays when the message gets processed. This directly improves resilience to downstream slowness, at the cost of the caller no longer getting an immediate answer — appropriate specifically when the caller doesn't need one.

Choosing based on consistency needs

The deciding question: does the caller need an immediate answer, or can the result be eventual? A checkout flow's "charge the card" step likely needs a synchronous answer (the user is waiting to know if payment succeeded). A checkout flow's "send a confirmation email" step doesn't — that's a natural fit for fire-and-forget async messaging, decoupling email-sending latency/failures entirely from the checkout response the user actually waits on.

Request-response vs fire-and-forget vs publish-subscribe

  • Request-response: caller sends a request, expects and waits for a specific reply (synchronous REST/gRPC, or an async request-reply pattern over messaging with a correlation ID).
  • Fire-and-forget: caller sends a message and moves on immediately, with no expectation of any reply at all (a logging event, an audit trail write).
  • Publish-subscribe: a producer publishes an event with no specific recipient in mind; zero, one, or many subscribers may independently react to it (see Observer Pattern for the same shape applied in-process) — the producer doesn't know or care who, if anyone, is listening.

The hybrid reality: most systems mix sync and async

A realistic e-commerce checkout: synchronous REST/gRPC for user-facing reads and the payment-charge step (the user is actively waiting), asynchronous messaging for background processing (inventory reservation confirmation, sending notifications, updating analytics) that doesn't block the user-visible response. Treating this as an either/or architectural choice for an entire system is a common design mistake — the right granularity is per-interaction, not per-system.

Feign vs RestTemplate vs WebClient

  • Feign — a declarative, interface-based HTTP client: define a Java interface with annotations describing the endpoint, and Feign generates the implementation — the most concise to write for typical service-to-service REST calls.
  • RestTemplate — the older, imperative/blocking client, explicitly in Spring's maintenance mode (no new features, though still supported) — mentioned mainly because it's common in existing/legacy codebases, not recommended for new code.
  • WebClient — the reactive, non-blocking client built for Spring WebFlux, returning Mono/Flux (see below) instead of blocking the calling thread — the modern default choice, especially in a service that itself needs to stay non-blocking end-to-end.

REST vs SOAP

REST is an architectural style over plain HTTP using standard verbs (GET/POST/PUT/DELETE) and typically JSON — lightweight, stateless, minimal tooling required. SOAP is a stricter, XML-based protocol with a formal contract (WSDL) and built-in standards for retry/security (the WS-* family) — heavier, but still common in enterprise and regulated integrations (banking, insurance, government systems) where SOAP's stronger built-in contracts and standardized security extensions are established requirements, not a stylistic preference.

Reactive programming: Mono and Flux, with backpressure

Mono<User> user = webClient.get().uri("/users/{id}", id).retrieve().bodyToMono(User.class); // 0-or-1 result
Flux<Order> orders = webClient.get().uri("/orders").retrieve().bodyToFlux(Order.class);      // 0-to-N results, streamed

Mono represents an asynchronous stream of 0 or 1 results; Flux represents 0 to N. Both carry built-in backpressure — a subscriber can signal how much data it's actually ready to consume, rather than a fast producer overwhelming a slower consumer's buffer, which is the core problem reactive streams (the specification Reactor implements) exist to solve. The practical payoff: a service can handle many concurrent I/O-bound requests on a small, fixed thread pool (no thread blocked per in-flight request the way a traditional synchronous servlet model requires), similar in spirit to virtual threads' I/O-bound scalability benefit but achieved through a fundamentally different mechanism (non-blocking callbacks and operator composition, not lightweight thread scheduling).

Follow-up questions this topic invites — and their answers

Q: If virtual threads make blocking-style code perform like async code, does reactive programming (WebClient/Mono/Flux) still matter? A: For many I/O-bound use cases, virtual threads (see Virtual Threads) do reduce the case for reactive code specifically for concurrency scaling — but Reactor's operator composition (retry, timeout, backpressure, combining multiple streams) offers expressive tools beyond just "don't block a thread," and existing WebFlux-based systems have substantial reasons to stay on the model they're already built around rather than a wholesale rewrite.

Q: When would gRPC be a poor choice despite its performance advantages? A: For a public-facing API consumed by arbitrary third-party clients (browsers, varied external tooling) where REST/JSON's universal support and human-debuggability matter more than internal service-to-service latency — gRPC's tooling and browser support (without a proxy layer like grpc-web) make it a much better fit for internal service-to-service traffic than for a public API surface.

Q: How does a request-response pattern work over an inherently asynchronous message broker? A: Via a correlation ID: the requester publishes a request message tagged with a unique ID and a reply-to destination, then asynchronously waits (or polls) for a response message carrying the same correlation ID on that destination — functionally request-response, but built on top of fundamentally async infrastructure rather than a direct synchronous call.

Q: Why might a team choose Feign over WebClient for simple service-to-service REST calls despite WebClient being the more 'modern' choice? A: If the calling service isn't itself reactive/non-blocking internally, Feign's simpler, more concise declarative style avoids introducing Mono/Flux-based reactive code into an otherwise traditional blocking codebase — reserving WebClient specifically for services already built on the reactive stack end-to-end avoids mixing two different concurrency models unnecessarily.

Previous

Service Discovery

Next

Event-Driven Architecture Patterns

AI Tutor

Lesson: Inter-Service Communication Choices

Quick actions

AI responses can be inaccurate. Verify critical information.