Scenario
Since the third-party API has a rate limit, I need to send requests one by one, with a delay between each call.
So I create a simple solution to do it!
Solution
// ApiService
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.Map;
@Slf4j
@Service
public class ApiService {
public void executeApi(BlockingQueueService.Request request) throws InterruptedException {
// log.info("[jobId-{}] API_SERVICE > START", request.getId());
Thread.sleep(request.getRunTime());
// log.info("[jobId-{}] API_SERVICE > STOP", request.getId());
}
}
// BlockingQueueService
import lombok.Data;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.concurrent.*;
@Slf4j
@Service
public class BlockingQueueService {
@Autowired
private ApiService apiService;
private final int POOL_SIZE = 1;
private final BlockingQueue<Request> queue = new LinkedBlockingQueue<>();
private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(POOL_SIZE);
public BlockingQueueService() {
log.info("INIT BLOCKING QUEUE SERVICE");
for (int i = 0; i < POOL_SIZE; i++) {
int workerId = i + 1;
executor.scheduleAtFixedRate(() -> processQueue(workerId), 0, 2, TimeUnit.SECONDS);
}
// executor.scheduleAtFixedRate(this::processQueue, 0, 1, TimeUnit.SECONDS);
}
public void enqueue(Request request) {
log.info("QUEUE > ADD: {}", request);
queue.offer(request);
}
private void processQueue(int workerId) {
Request request = queue.poll();
log.info("[worker-{}] QUEUE > CHECK", workerId);
if (request == null) {
return;
}
log.info("[worker-{}__jobId-{}] QUEUE > PROCESS START", workerId, request.getId());
try {
this.apiService.executeApi(request);
} catch (Exception e) {
e.printStackTrace();
} finally {
log.info("[worker-{}__jobId-{}] QUEUE > PROCESS END", workerId, request.getId());
}
}
@Data
@ToString
public static class Request {
int id;
int runTime;
}
}
// Queue101Application
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
@RestController
@SpringBootApplication
public class Queue101Application {
@Autowired
BlockingQueueService blockingQueueService;
private int count = 0;
public static void main(String[] args) {
SpringApplication.run(Queue101Application.class, args);
}
@GetMapping("/trigger")
public String trigger() {
for (int i = 0; i < 100; i++) {
BlockingQueueService.Request request = new BlockingQueueService.Request();
int randomNumber = ThreadLocalRandom.current().nextInt(1,2);
request.setId(count);
request.setRunTime(randomNumber*1000);
count++;
blockingQueueService.enqueue(request);
}
return "SUCCESS";
}
}
Test
- Trigger queue: http://localhost:8080/trigger
- Log
...
2025-04-17T21:22:44.409+09:00 INFO 88153 --- [queue101] [nio-8080-exec-1] o.h.queue101.BlockingQueueService : QUEUE > ADD: BlockingQueueService.Request(id=99, runTime=1000)
2025-04-17T21:22:45.799+09:00 INFO 88153 --- [queue101] [pool-2-thread-1] o.h.queue101.BlockingQueueService : [worker-1] QUEUE > CHECK
2025-04-17T21:22:45.799+09:00 INFO 88153 --- [queue101] [pool-2-thread-1] o.h.queue101.BlockingQueueService : [worker-1__jobId-0] QUEUE > PROCESS START
2025-04-17T21:22:46.799+09:00 INFO 88153 --- [queue101] [pool-2-thread-1] o.h.queue101.BlockingQueueService : [worker-1__jobId-0] QUEUE > PROCESS END
2025-04-17T21:22:47.800+09:00 INFO 88153 --- [queue101] [pool-2-thread-1] o.h.queue101.BlockingQueueService : [worker-1] QUEUE > CHECK
2025-04-17T21:22:47.801+09:00 INFO 88153 --- [queue101] [pool-2-thread-1] o.h.queue101.BlockingQueueService : [worker-1__jobId-1] QUEUE > PROCESS START
2025-04-17T21:22:48.806+09:00 INFO 88153 --- [queue101] [pool-2-thread-1] o.h.queue101.BlockingQueueService : [worker-1__jobId-1] QUEUE > PROCESS END
...