Skip to content

[Bug]: 비동기 스케쥴링 간 레이스 컨디션 #41

@h-beeen

Description

@h-beeen

Bug description

현재 구현

    private final ScheduledExecutorService scheduler;
    private final Executor virtualThreadExecutor;

문제점 :

  • I/O 작업을 일정 간격으로 비동기 실행하기 위한 방법으로, ScheduledExecutorService 구현체를 통해,
    0.7초 간격으로 비동기 호출하는 로직
  • 스케쥴러가 이전 작업을 0.7초 간격으로 스케쥴링 하는 중, 새로운 작업이 요청되면 기존 작업과 레이스컨디션이 발생해,
    Lock에 의해 스케쥴러가 RejectedExecutionException을 맞딱뜨리게 됨
  • 비관적 락으로 인해 스케줄러가 직렬화되어 있어서 새로운 요청이 계속적으로 스케쥴링을 대기하는 상태

Expected behavior

AS-IS

  • Case 1. 현 개선안
    requestMultipleProduct(3건) -> 3건을 0.7초 간격으로 I/O 요청
    requestMultipleProduct(5건) -> 3건의 I/O 요청이 모두 끝난 뒤, 5건을 0.7초 간격으로 I/O 요청

  • Case 2. HotFix 개선안
    requestMultipleProduct(3건) -> 3건을 0.7초 간격으로 I/O 요청
    requestMultipleProduct(5건) -> 3건의 I/O 요청이 모두 끝난 뒤 [Not Callback] , 5건을 0.7초 간격으로 I/O 요청
    requestMultipleProduct(10건) -> 8건의 I/O 요청이 모두 끝난 뒤, 10건을 0.7초 간격으로 I/O 요청

-> 스케쥴러 자체를 비관적 Lock으로 구현하면서 요청이 많아질 때 요청 스케쥴링 자체가 지연.

TO-BE

requestMultipleProduct(3건) -> 3건을 0.7초 간격으로 I/O 요청
requestMultipleProduct(5건) -> 위 요청건을 진행하는 것과 별도의 비동기로 5건을 0.7초 간격으로 I/O 요청

To Reproduce

  1. Reactor의 Flux 사용
  • WebFlux와 연동성 향상. But 너무 무거운 SDK로 발전
  1. ScheduledExecutorService + BlockingQueue
BlockingQueue<EasyCodefRequest> queue = new LinkedBlockingQueue<>(requests);
scheduler.scheduleAtFixedRate(
    () -> {
        EasyCodefRequest request = queue.poll();
        if (request != null) {
            executeRequest(request);
        }
    },
    0, 700, TimeUnit.MILLISECONDS
);
  1. Kotlin + Coroutine

Possible Solution

No response

etc.

No response

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions