DEV Community

Cover image for Handling Concurrent API Calls in Spring Boot
özkan pakdil
özkan pakdil

Posted on • Originally published at ozkanpakdil.github.io on

Handling Concurrent API Calls in Spring Boot

When building Spring Boot applications, handling concurrent API calls efficiently is crucial to ensure optimal performance and scalability. Here are a few approaches to manage concurrent read and write operations:

Handling Concurrent Read API Calls

Asynchronous Methods

Using @Async at @Service annotation and enabling asynchronous processing can help handle multiple API calls concurrently.

@Async
public CompletableFuture<String> asyncMethod() {
    // Call external API
    return CompletableFuture.completedFuture("Result");
}

Enter fullscreen mode Exit fullscreen mode

WebClient with Reactor

Spring WebFlux’s WebClient allows for reactive programming, making it easier to handle multiple API calls.

Mono<String> firstApiCall = webClient.get().uri("http://example.com/api1").retrieve().bodyToMono(String.class);
Mono<String> secondApiCall = webClient.get().uri("http://example.com/api2").retrieve().bodyToMono(String.class);

return Mono.zip(firstApiCall, secondApiCall)
        .map(tuple -> tuple.getT1() + " " + tuple.getT2());

Enter fullscreen mode Exit fullscreen mode

ExecutorService

Using ExecutorService allows for creating a pool of threads to manage concurrent calls.

private final ExecutorService executorService = Executors.newFixedThreadPool(10);

public CompletableFuture<String> makeConcurrentCall() {
    return CompletableFuture.supplyAsync(() -> "Result", executorService);
}

Enter fullscreen mode Exit fullscreen mode

Parallel Streams

Java 8’s parallel streams can perform API calls in parallel.

return Stream.of("http://example.com/api1", "http://example.com/api2")
    .parallel()
    .map(url -> "Result from " + url)
    .collect(Collectors.toList());

Enter fullscreen mode Exit fullscreen mode

Handling Concurrent Write API Calls

Handling concurrent write operations, such as updates, requires careful management to ensure data consistency. Here are a few strategies:

Synchronized Blocks

Using synchronized blocks ensures that only one thread can execute a block of code at a time.

public synchronized String updateData(String url, Object data) {
    return webClient.post().uri(url).bodyValue(data).retrieve().bodyToMono(String.class).block();
}

Enter fullscreen mode Exit fullscreen mode

Optimistic Locking

Optimistic locking uses versioning to handle concurrent updates, ensuring data consistency.

class Item {
    // Other fields
    @Version
    private Long version;
}
public Item updateItem(Item newItem) {
    return repository.save(newItem);
}

Enter fullscreen mode Exit fullscreen mode

@Transactional with Retry

The @Transactional annotation combined with retry mechanisms can handle transaction conflicts. This is also used in @Service layer.

@Transactional
@Retryable(value = {OptimisticLockingFailureException.class}, maxAttempts = 3, backoff = @Backoff(delay = 500))
public Item updateItem(Item newItem) {
    return repository.save(newItem);
}

Enter fullscreen mode Exit fullscreen mode

Distributed Locks

Using distributed locks like Redis ensures that only one service instance can perform the update at a time.

RLock lock = redissonClient.getLock("updateLock");
lock.lock();
try {
    // Perform the write call
} finally {
    lock.unlock();
}

Enter fullscreen mode Exit fullscreen mode

By employing these techniques, concurrent API calls within a Spring Boot application can be efficiently managed, thus ensuring optimal performance and maintaining data integrity.

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay