공공부하자개발 · 영어 학습 노트
자바
실무 확장Excel · 파일 업로드 · DB 연동0/22 완료
  • 01Excel(XLSX) 구조와 순수 JDK로 읽기/쓰기
  • 02Apache POI로 Excel 업로드/다운로드
  • 03파일 업로드/다운로드 서버 (HttpServer)
  • 04JDBC 기초와 트랜잭션 (H2)
  • 05MyBatis 어노테이션 매퍼로 쿼리 연동
  • 06MyBatis XML 매퍼 · Oracle 방언 · PageHelper · Spring Boot
  • 07REST API 서버와 JSON
  • 08Vue 3 SPA 와 Java 서버 연동
  • 09@Scheduled 운영
  • 10로깅 실무: 레벨·계층, MDC 추적, 예외·성능, 마스킹, 롤링, JSON 로그
  • 11외부 API 연동
  • 12테스트 실무
  • 13암호화·개인정보 보호
  • 14인코딩·한글 실무
  • 15@Transactional 심화
  • 16긴 작업 비동기 처리와 진행률
  • 17SFTP·FTP 파일 연계
  • 18로컬 캐시와 @Cacheable
  • 19메일·알림 발송
  • 20웹 보안 체크리스트
  • 21빌드 도구와 폐쇄망 의존성 반입
  • 22성능 측정: p50·p95·p99, 측정 계층, JFR, JMH 함정, 자체 부하 테스트, 병목 순위
사이트 소개개인정보처리방침연락처
© 2026 공부하자
홈 › 실무 확장 › 16 / 22

긴 작업 비동기 처리와 진행률

202 Accepted, 작업 상태, 폴링·SSE, 취소, 중복 방지, 완전 종료
섹션 7진행 0 / 22
1왜 배우는가2핵심 원리3코드 예제4응용 변형 예제5자주 하는 실수 (Tip)6연습 문제7정리‹ 이전다음 ›

4. 응용 변형 예제

4.1 Spring @Async + ThreadPoolTaskExecutor

java
@EnableAsync
@Configuration
class AsyncConfig {
    @Bean
    ThreadPoolTaskExecutor jobExecutor() {
        ThreadPoolTaskExecutor ex = new ThreadPoolTaskExecutor();
        ex.setCorePoolSize(2);
        ex.setMaxPoolSize(2);
        ex.setQueueCapacity(10);
        ex.setThreadNamePrefix("job-");
        return ex;
    }
}

@Service
class SettlementService {
    @Async("jobExecutor")
    public void runSettlement(String jobId) {
        // 긴 정산 로직, 완료 시 JOB 테이블 갱신
    }
}

컨트롤러는 runSettlement 을 호출하자마자 리턴하므로 202 응답을 바로 만들 수 있습니다. @Async 메서드의 리턴 타입이 void 면 예외가 호출자에게 전달되지 않으니, 실패는 반드시 메서드 내부에서 잡아 JOB 테이블에 FAILED 로 기록해야 합니다.

4.2 SseEmitter 로 진행률 push

java
@GetMapping("/jobs/{id}/events")
public SseEmitter events(@PathVariable String id) {
    SseEmitter emitter = new SseEmitter(0L); // 타임아웃 없음
    jobExecutor.execute(() -> {
        try {
            while (진행중) {
                emitter.send(SseEmitter.event().data(statusJson(id)));
                Thread.sleep(500);
            }
            emitter.complete();
        } catch (Exception e) {
            emitter.completeWithError(e);
        }
    });
    return emitter;
}

SseEmitter 는 완료·에러 콜백(onCompletion, onTimeout)을 등록해 클라이언트 연결이 끊겼을 때 리소스를 정리할 수 있습니다. nginx 설정은 2.4 절과 동일하게 버퍼링을 꺼야 합니다.

4.3 self-invocation 함정 재현

java
@Service
class JobService {
    public void submitAndRun(String id) {
        this.runAsync(id); // 같은 빈 안에서 직접 호출
    }

    @Async
    public void runAsync(String id) {
        // 이 메서드는 프록시를 거치지 않아 동기 실행된다
    }
}

submitAndRun 안에서 this.runAsync(id) 를 호출하면 @Async 가 무시되고 같은 스레드에서 즉시 실행됩니다. 컨트롤러가 submitAndRun 을 호출하는 순간 요청 스레드가 그대로 긴 작업을 떠안습니다. 해결책은 runAsync 를 별도 빈으로 분리해 프록시를 통해 호출하는 것입니다.

응용 변형 예제
  • 4.1 Spring @Async + ThreadPoolTaskExecutor
  • 4.2 SseEmitter 로 진행률 push
  • 4.3 self-invocation 함정 재현
이전 섹션3 코드 예제4 / 7다음 섹션5 자주 하는 실수 (Tip)