Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- api 요청 수 제한
- Dev-Matching
- this
- 음악 url 파일 다운로드
- 모던 자바스크립트
- 타입스크립트
- bucket4j
- compateto
- 스프링부트
- 프론트엔드 과제
- 우아한테크코스
- 딥다이브
- 우아한 테크코스
- 프리코스
- 자바스크립트
- AWS
- NestJS
- 코멘토 #코멘토실무PT #실무PT후기 #실무강의 #리액트강의 #웹프로그래밍 #react #웹개발실무
- 검색
- 파일 url
- 유효시간 설정 url
- invalid_grant
- TypeORM
- 프론트엔드
- 프로그래머스
- redis
- Deep Dive
- api 비동기처리
- concurrency limit
- oauth
Archives
- Today
- Total
개발 알다가도 모르겠네요
[Spring] @Async를 이용해 비동기 처리를 해보자 본문
728x90
기존에는 일기를 작성하면 내부적으로는 '일기 생성 -> GPT로 일기 감정 추출 -> Suno AI로 음악생성 -> 일기 생성 완료' 의 로직으로 돌아가고 있어 클라이언트가 응답을 받는데까지 7~8초가 소요됐다.
따라서 비동기 처리를 활용하면 장기 실행 작업이 메인 스레드를 차단하지 않도록 하여 사용자 응답 시간을 줄이고 시스템 자원을 효율적으로 사용할 수 있도록 구현했다.
비동기 처리를 위한 AsyncConfig 클래스
비동기 처리를 위한 설정 클래스를 작성한다. AsyncConfig 클래스는 Spring의 비동기 기능을 활성화하고, ThreadPoolTaskExecutor를 설정하여 비동기 작업을 처리할 때 사용할 스레드 풀을 구성한다.
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean(name = "taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10); // 코어 스레드 풀 크기 설정
executor.setMaxPoolSize(50); // 최대 스레드 풀 크기 설정
executor.setQueueCapacity(100); // 대기열 크기 설정
executor.setThreadNamePrefix("Async-"); // 스레드 이름 접두사 설정
executor.initialize();
return executor;
}
}
DiaryService 클래스
DiaryService 클래스는 일기와 관련된 비즈니스 로직을 처리한다. 일기를 생성하고 비동기로 GPT 프롬프트 생성&음악 생성을 처리한다.
@Service
public class DiaryService {
private final UserRepository userRepository;
private final DiaryRepository diaryRepository;
private final ChatGPTService chatGPTService;
private final MusicService musicService;
public DiaryService(UserRepository userRepository, DiaryRepository diaryRepository, ChatGPTService chatGPTService, MusicService musicService) {
this.userRepository = userRepository;
this.diaryRepository = diaryRepository;
this.chatGPTService = chatGPTService;
this.musicService = musicService;
}
@Transactional
public DiaryCreateResponseDto createDiary(Long userId, DiaryCreateRequestDto diaryCreateRequestDto) {
try {
User user = userRepository.findById(userId)
.orElseThrow(() -> new UserException("해당하는 사용자를 찾을 수 없습니다."));
Diary diary = diaryCreateRequestDto.toEntity(diaryCreateRequestDto, user);
Diary savedDiary = diaryRepository.save(diary);
return DiaryCreateResponseDto.of(savedDiary);
} catch (Exception e) {
throw new DiaryException("Diary 생성 중 오류가 발생했습니다. " + e.getMessage());
}
}
@Async
public void handleDiaryCreationAsync(Long diaryId) {
try {
generatePromptAsync(diaryId);
generateMusicAsync(diaryId);
} catch (Exception e) {
log.error("Diary 추가 작업 중 오류가 발생했습니다. " + e.getMessage());
}
}
@Async
public void generatePromptAsync(Long diaryId) {
try {
Diary diary = diaryRepository.findById(diaryId)
.orElseThrow(() -> new DiaryException("Diary not found with id: " + diaryId));
PromptRequestDto promptRequestDto = new PromptRequestDto(diary.getContent());
PromptResponseDto promptResponseDto = chatGPTService.sendPrompt(promptRequestDto, PromptType.CONTENT_EMOTION_ANALYSIS);
String updatedPrompt = diary.getPrompt() + " , " + promptResponseDto.getContent();
diary.setPrompt(updatedPrompt);
diaryRepository.save(diary);
} catch (Exception e) {
log.error("GPT 프롬프트 처리 중 오류가 발생했습니다. " + e.getMessage());
}
}
@Async
public void generateMusicAsync(Long diaryId) {
try {
Diary diary = diaryRepository.findById(diaryId)
.orElseThrow(() -> new DiaryException("Diary not found with id: " + diaryId));
MusicCreateRequestDto musicCreateRequestDto = new MusicCreateRequestDto();
musicCreateRequestDto.setDiaryId(diary.getId());
musicCreateRequestDto.setGenerationPrompt(diary.getPrompt());
musicService.createMusic(musicCreateRequestDto);
} catch (Exception e) {
log.error("음악 생성 중 오류가 발생했습니다. " + e.getMessage());
}
}
}
기술적 인사이트
- 비동기 처리의 장점: 비동기 처리를 통해 여러 작업을 동시에 처리할 수 있으므로, 사용자 요청에 대한 응답 시간을 단축할 수 있었다. 일기 작성 후 감정 분석 및 음악 생성과 같은 시간이 오래 걸리는 작업을 비동기로 처리했기 때문에 UX 측면에서 개선됐다.
- ThreadPoolTaskExecutor 설정: 비동기 작업의 효율적인 처리를 위해 ThreadPoolTaskExecutor를 사용하여 스레드 풀을 설정하였다. 코어 스레드 풀 크기, 최대 스레드 풀 크기, 대기열 크기 등을 설정하여 다양한 작업 부하를 처리할 수 있도록 구성했다.
- 비동기 메서드 구현: Spring의 @Async 애노테이션을 사용하여 비동기 메서드를 구현하였다. 일기 생성 후, GPT 프롬프트 생성 및 음악 생성을 비동기 메서드로 처리하여 메인 프로세스의 성능을 저하시키지 않도록 했다.
@Async
public void handleDiaryCreationAsync(Long diaryId) {
try {
generatePromptAsync(diaryId);
generateMusicAsync(diaryId);
} catch (Exception e) {
log.error("Diary 추가 작업 중 오류가 발생했습니다. " + e.getMessage());
}
}
'웹 > Spring' 카테고리의 다른 글
[Spring] AWS S3 + CloudFront를 활용해서 음악 공유 URL을 만들어보자 (0) | 2024.05.27 |
---|---|
[Spring] SunoAI와 Spring Boot를 연동해보자 (0) | 2024.05.15 |
[Spring] 애플 소셜 로그인을 구현해보자 (0) | 2024.05.01 |
[Spring] Concurrency/Rate Limiter를 적용하여 API 요청을 제어해보자 (0) | 2023.08.25 |
Controller에서 jsp return하는 과정 (0) | 2023.02.21 |