'How to shortly delay a http request until a resource is free

I have a small spring-boot application, let's say it is called "ABC" which has to get a part of information from an external web-service, let's call it "ext resource". The problem is that the policy of that external service doesn't allow more than 60 requests per minute. Otherwise I would get a warning from them. I searched the web, but couldn't find any solution for this. I was thinking to limit requests to 1 request per second (which then comes to 60 requests per minute).

When clients (browser) send requests to my "ABC" server, how can I distribute them into 1 second raster? Asked another way, if necessary, how can I delay http requests, until "ext resource" is free again? In the period of 1 sec. only one client's request may use "ext resource". First thought I had was to do Thread.sleep(1000) and then re-check if "the resource" is free, but I'm not sure if I should use Thread.sleep inside a web-app running on Apache Tomcat. I guess I cannot use any ansynchronous methods, because clients must wait for some results, so the whole request must be synchronous. I "just" need to delay client's request for a while until my server-side application "ABC" is allowed to contact "ext resourse" again. How can I do this and which technique would you recommend for this kind of "synchronization"?

I'm kind of old-school Java Developer and still not into this newer stuff like Futures/Promises. I took a look at them, but from what I saw that's all asynchronous stuff (I searched in Internet for some hours now).

Thank you very much for any help!



Solution 1:[1]

You could do something like this:

import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class RequestThrottlerService {

    AtomicInteger requestCount = new AtomicInteger(1);
    
    /** Every minute **/
    @Scheduled(cron = "0 * * * * *")
    synchronized public void resetRequests() {
        log.info("Reset the request count.");
        requestCount.set(1);
        notifyAll();
    }

    public void makeThrottledRequest() throws InterruptedException {
        
        int count = requestCount.getAndIncrement();
        while (count > 60) {
            synchronized(this) {
                log.info("Request " + requestCount.get() + " for this minute is waiting!");
                wait(); 
            }
            count = requestCount.getAndIncrement();
        }
        log.info("Request " + requestCount.get() + " for this minute is running");
        /* ##### execute your synchronous request here ##### */ 
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Hopey One