Search
Calendar
June 2025
S M T W T F S
« May    
1234567
891011121314
15161718192021
22232425262728
2930  
Archives

Posts Tagged ‘SpringBoot’

PostHeaderIcon Efficient Inter-Service Communication with Feign and Spring Cloud in Multi-Instance Microservices

In a world where systems are becoming increasingly distributed and cloud-native, microservices have emerged as the de facto architecture. But as we scale
microservices horizontally—running multiple instances for each service—one of the biggest challenges becomes inter-service communication.

How do we ensure that our services talk to each other reliably, efficiently, and in a way that’s resilient to failures?

Welcome to the world of Feign and Spring Cloud.


The Challenge: Multi-Instance Microservices

Imagine you have a user-service that needs to talk to an order-service, and your order-service runs 5 instances behind a
service registry like Eureka. Hardcoding URLs? That’s brittle. Manual load balancing? Not scalable.

You need:

  • Service discovery to dynamically resolve where to send the request
  • Load balancing across instances
  • Resilience for timeouts, retries, and fallbacks
  • Clean, maintainable code that developers love

The Solution: Feign + Spring Cloud

OpenFeign is a declarative web client. Think of it as a smart HTTP client where you only define interfaces — no more boilerplate REST calls.

When combined with Spring Cloud, Feign becomes a first-class citizen in a dynamic, scalable microservices ecosystem.

✅ Features at a Glance:

  • Declarative REST client
  • Automatic service discovery (Eureka, Consul)
  • Client-side load balancing (Spring Cloud LoadBalancer)
  • Integration with Resilience4j for circuit breaking
  • Easy integration with Spring Boot config and observability tools

Step-by-Step Setup

1. Add Dependencies

If using Eureka:


2. Enable Feign Clients

In your main Spring Boot application class:

@SpringBootApplication
@EnableFeignClients
        public <span>class <span>UserServiceApplication { ... }

3. Define Your Feign Interface

    @FeignClient(name = "order-service")
    public interface OrderClient { @GetMapping("/orders/{id}")
        OrderDTO getOrder(@PathVariable("id") Long id); }

Spring will automatically:

  • Register this as a bean
  • Resolve order-service from Eureka
  • Load-balance across all its instances

4. Add Resilience with Fallbacks

You can configure a fallback to handle failures gracefully:


@FeignClient(name = "order-service", fallback = OrderClientFallback.class)
public interface    OrderClient {
        @GetMapping("/orders/{id}") OrderDTO  getOrder(@PathVariable Long id);
            }

The fallback:


@Component
public class OrderClientFallback implements OrderClient {
@Override public    OrderDTO getOrder(Long id) {
return new    OrderDTO(id, "Fallback Order", LocalDate.now());
}
}

⚙️ Configuration Tweaks

Customize Feign timeouts in application.yml:

[yml]

feign:

    client:

       config:

           default:

                connectTimeout:3000

                readTimeout:500

[/yml]

Enable retry:

        feign:
        client:
        config:
        default:
        retryer:
        maxAttempts: 3
        period: 1000
        maxPeriod: 2000

What Happens Behind the Scenes?

When user-service calls order-service:

  1. Spring Cloud uses Eureka to resolve all instances of order-service.
  2. Spring Cloud LoadBalancer picks an instance using round-robin (or your chosen strategy).
  3. Feign sends the HTTP request to that instance.
  4. If it fails, Resilience4j (or your fallback) handles it gracefully.

Observability & Debugging

Use Spring Boot Actuator to expose Feign metrics:


<dependency>
        <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency

And tools like Spring Cloud Sleuth + Zipkin for distributed tracing across Feign calls.


Beyond the Basics

To go even further:

  • Integrate with Spring Cloud Gateway for API routing and external access.
  • Use Spring Cloud Config Server to centralize configuration across environments.
  • Secure Feign calls with OAuth2 via Spring Security and OpenID Connect.

✨ Final Thoughts

Using Feign with Spring Cloud transforms service-to-service communication from a tedious, error-prone task into a clean, scalable, and cloud-native solution.
Whether you’re scaling services across zones or deploying in Kubernetes, Feign ensures your services communicate intelligently and resiliently.

PostHeaderIcon SpringBatch: How to have different schedules, per environment, for instance: keep the fixedDelay=60000 in prod, but schedule with a Cron expression in local dev?

Case

In SpringBatch, a batch is scheduled in a bean JobScheduler with

@Scheduled(fixedDelay = 60000)
void doSomeThing(){...}

.
How to have different schedules, per environment, for instance: keep the fixedDelay=60000 in prod, but schedule with a Cron expression in local dev?

Solution

Add this block to the <JobScheduler:

	@Value("${jobScheduler.scheduling.enabled:true}")
	private boolean schedulingEnabled;

	@Value("${jobScheduler.scheduling.type:fixedDelay}")
	private String scheduleType;

	@Value("${jobScheduler.scheduling.fixedDelay:60000}")
	private long fixedDelay;

	@Value("${jobScheduler.scheduling.initialDelay:0}")
	private long initialDelay;

	@Value("${jobScheduler.scheduling.cron:}")
	private String cronExpression;

	@Scheduled(fixedDelayString = "${jobScheduler.scheduling.fixedDelay:60000}", initialDelayString = "${jobScheduler.scheduling.initialDelay:0}")
	@ConditionalOnProperty(name = "jobScheduler.scheduling.type", havingValue = "fixedDelay")
	public void scheduleFixedDelay() throws Exception {
		if ("fixedDelay".equals(scheduleType) || "initialDelayFixedDelay".equals(scheduleType)) {
			doSomething();
		}
	}

	@Scheduled(cron = "${jobScheduler.scheduling.cron:0 0 1 * * ?}")
	@ConditionalOnProperty(name = "jobScheduler.scheduling.type", havingValue = "cron", matchIfMissing = false)
	public void scheduleCron() throws Exception {
		if ("cron".equals(scheduleType)) {
			doSomething();		}
	}

In application.yml, add:

jobScheduler:
  # noinspection GrazieInspection
  scheduling:
    enabled: true
    type: fixedDelay
    fixedDelay: 60000
    initialDelay: 0
    cron: 0 0 1 31 2 ? # every 31st of February... which means: never

(note the cron expression: leaving it empty may prevent SpringBoot from starting)

In application.yml, add:

jobScheduler:
  # noinspection GrazieInspection
  scheduling:
    type: cron
    cron: 0 0 1 * * ?

It should work now ;-).