ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

Spring MVC์—์„œ ํ”„๋กœ์„ธ์Šค๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋™๊ธฐ์‹ ์ฒ˜๋ฆฌ๋กœ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค.

์ฝ”๋“œ ํ•œ์ค„ํ•œ์ค„ ์ฐจ๋ก€๋Œ€๋กœ ์‹คํ–‰์ด ์™„๋ฃŒ๋œ ํ›„ ๋„˜์–ด๊ฐˆ ์ˆ˜ ์žˆ๋‹ค๋Š” ๋œป์ด์ฃ . ๋ณดํ†ต ์ด๊ฑธ Blocking ์ด๋ผ๊ณ  ํ•˜๊ณ  ๋ฐ˜๋Œ€๊ฐ€ ๋˜๋Š” ๋ง์€ Non-Blocking ์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ๊ฐ€ ์ฐจ๋ก€๋Œ€๋กœ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ ์‹คํ–‰์— ๋”ฐ๋ฅธ ๊ฒฐ๊ณผ ๊ฐ’์„ ๋ณด๋Š”๊ฒŒ ๋ช…ํ™•ํ•œ ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

 

Node.js๋กœ ๊ฐœ๋ฐœ์„ ์ข€ ํ•ด์˜ค๋‹ค๋ณด๋‹ˆ (Node.js๋Š” ๋ฐ˜๋Œ€๋กœ ๋น„๋™๊ธฐ์ฒ˜๋ฆฌ๊ฐ€ ๊ธฐ๋ณธ ์ปจ์…‰์ž…๋‹ˆ๋‹ค.) Async์— ๋Œ€ํ•œ ์šฉ์–ด์— ๋” ๋ˆˆ์ด๊ฐ€์„œ Spring ์–ด๋…ธํ…Œ์ด์…˜์ค‘ @Async ์–ด๋…ธํ…Œ์ด์…˜์— ๋จผ์ € ๋ˆˆ์ด ๊ฐ”์Šต๋‹ˆ๋‹ค. ์–ด๋…ธํ…Œ์ด์…˜ ํ•˜๋‚˜๋งŒ ์ถ”๊ฐ€ํ•˜๋ฉด ๋‚ด๊ฐ€ ์›ํ•˜๋Š”๊ฒŒ ๋œ๋‹ค?

 

@Async

@Async๋Š” Spring ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ๋น„๋™๊ธฐ์ ์ธ ๋ฉ”์„œ๋“œ ์‹คํ–‰์„ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•œ ์–ด๋…ธํ…Œ์ด์…˜์ž…๋‹ˆ๋‹ค. ์ด ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ฉ”์„œ๋“œ์— ๋ถ™์ด๋ฉด ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋Š” ๋ณ„๋„์˜ ์“ฐ๋ ˆ๋“œ์—์„œ ์‹คํ–‰๋˜๋ฉฐ, ํ˜ธ์ถœํ•œ ์“ฐ๋ ˆ๋“œ๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋ธ”๋กœํ‚น๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. @Async๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋™๊ธฐ์ ์ธ ๋ฐฉ์‹์ด ์•„๋‹Œ ๋น„๋™๊ธฐ์ ์ธ ๋ฐฉ์‹์œผ๋กœ ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๋ฉ”์†Œ๋“œ์— ๊ทธ๋ƒฅ ์–ด๋…ธํ…Œ์ด์…˜๋งŒ ๋ถ™์ด๋ฉด Async ๋ฉ”์†Œ๋“œ๊ฐ€ ๋˜๋Š” ๊ฒƒ์ธ๊ฐ€? ํ–ˆ์ง€๋งŒ @Async๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ฃผ์˜ํ•  ์ ์€ ์ด ์–ด๋…ธํ…Œ์ด์…˜๋„ Thread pool์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ฌด๋ถ„๋ณ„ํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋ฉด ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜๋„ ์žˆ๊ณ , ์Šคํ”„๋ง์˜ ํ”„๋ก์‹œ ๋งค์ปค๋‹ˆ์ฆ˜์„ ํ†ตํ•ด ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ๊ตฌํ˜„๋˜๊ธฐ ๋•Œ๋ฌธ์— @Async ๋ฉ”์„œ๋“œ๋Š” ๊ฐ™์€ ํด๋ž˜์Šค ๋‚ด์—์„œ ํ˜ธ์ถœ๋˜๋ฉด ๋น„๋™๊ธฐ์ ์œผ๋กœ ์‹คํ–‰๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ AOP ํ”„๋ก์‹œ๊ฐ€ ์ ์šฉ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

 

์ €๊ฐ™์€ ๊ฒฝ์šฐ๋„ Spring MVC ํ”„๋กœ์ ํŠธ์— ๊ธฐ๋ณธ์ ์œผ๋กœ Filter๋ฅผ ์‚ฌ์šฉํ•˜๊ณ ์žˆ๋Š”๋ฐ ์œ„ ๋‚ด์šฉ๋•Œ๋ฌธ์— ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๋ถ€๋ถ„์„ ํ™•์ธํ•˜๊ณ  ๋ฐ”๋กœ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์ฐพ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค.

 

ThreadPoolTaskExecutor

์Šคํ”„๋ง์—์„œ ์ œ๊ณตํ•ด์ฃผ๋Š” ํด๋ž˜์Šค๋กœ ์“ฐ๋ ˆ๋“œํ’€์„ ์ด์šฉํ•˜์—ฌ ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ ๊ตฌํ˜„์„ ์‰ฝ๊ฒŒ ํ•ด์ฃผ๋Š” ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค.

์ผ๋‹จ ์ œ๊ฐ€ ์˜๋„ํ•œ ๋ถ€๋ถ„์€ API ํ˜ธ์ถœ ์‹œ์— ๋‚ด๋ถ€ ์ฒ˜๋ฆฌ์™€ ์ƒ๊ด€์—†์ด ๋น ๋ฅด๊ฒŒ ์‘๋‹ต ๊ฐ’์„ ์ฃผ๋Š”๊ฑธ ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๊ธฐ์œ„ํ•ด์„  ๋ถ€ํ•˜๊ฐ€ ํฐ Service ๋ฉ”์†Œ๋“œ์— ๋Œ€ํ•œ Async ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ–ˆ๊ณ , ์•„๋ž˜์™€๊ฐ™์ด ์ฒ˜๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

 

AsyncConfig.class

: ์“ฐ๋ ˆ๋“œํ’€์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ custom ์„ค์ •์„ ํ•˜๋Š” ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค.

@Configuration
public class AsyncConfig {

    @Bean
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);  // ์“ฐ๋ ˆ๋“œํ’€์˜ ๊ธฐ๋ณธ ํฌ๊ธฐ
        executor.setMaxPoolSize(50);   // ์“ฐ๋ ˆ๋“œํ’€์˜ ์ตœ๋Œ€ ํฌ๊ธฐ
        executor.setQueueCapacity(100); // ์ž‘์—… ํ ํฌ๊ธฐ
        executor.setThreadNamePrefix("Custom-Async-"); // ์“ฐ๋ ˆ๋“œ ์ด๋ฆ„ ์ ‘๋‘์‚ฌ ์„ค์ •
        executor.initialize();
        return executor;
    }
}

 

Controller์ฝ”๋“œ

: ์„œ๋น„์Šค ๋ฉ”์†Œ๋“œ๋ฅผ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋กœ์ง์œผ๋กœ ์ˆ˜์ •ํ•˜์˜€๊ณ , DeferredResult ๊ฐ์ฒด์— ๋น„๋™๊ธฐ๋กœ์ง์— ๋Œ€ํ•œ ๊ฒฐ๊ณผ ๊ฐ’์„ ์ €์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@RequiredArgsConstructor
public class AlarmController {
    private final AlarmService alarmService;
    @Qualifier("taskExecutor")
    private final ThreadPoolTaskExecutor taskExecutor;

   @PostMapping(value = "/{id}/send")
   public Response<Map<String,Object>> immediatelyPush(
           HttpServletRequest req,
           @PathVariable("id") Long id
   ) {
       try {
           // DeferredResult<Response<Map<String, Object>>> deferredResult = new DeferredResult<>();

           taskExecutor.submit(() -> {
               // ๋น„๋™๊ธฐ๋กœ ์‹คํ–‰๋˜๋Š” ๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋กœ์ง
               alarmService.immediatelyPush(id);
               // deferredResult.setResult(new Response<>(ResultCode.REGISTER_SUCCESS));
               // deferredResult.setResult(new Response<>(ResultCode.REGISTER_FAIL));
           });
           return new Response<>(ResultCode.REGISTER_SUCCESS);
       } catch (Exception e) {
           return new Response<>(ResultCode.REGISTER_FAIL);
       }
   }
}

์ด๋ ‡๊ฒŒ๋˜๋ฉด ์„œ๋น„์Šค ๋ฉ”์†Œ๋“œ์— ๋Œ€ํ•œ ๋ถ€๋ถ„์ด ์‹คํ–‰์™„๋ฃŒ๋˜์ง€์•Š์•„๋„ ์ฆ‰์‹œ response๋ฅผ ๋„˜๊ฒจ์ฃผ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋ฌผ๋ก  responseํ›„์—๋„ Spring Application ์—์„œ๋Š” ํ•ด๋‹น ๋กœ์ง์ด ์‹คํ–‰์ค‘์ด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

 

'spring๐Ÿƒ' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

Spring boot์—์„œ Http request ๋น„๋™๊ธฐ ์š”์ฒญํ•˜๊ธฐ  (0) 2023.10.26
๋Œ“๊ธ€
๊ณต์ง€์‚ฌํ•ญ
์ตœ๊ทผ์— ์˜ฌ๋ผ์˜จ ๊ธ€
์ตœ๊ทผ์— ๋‹ฌ๋ฆฐ ๋Œ“๊ธ€
Total
Today
Yesterday
๋งํฌ
ยซ   2025/05   ยป
์ผ ์›” ํ™” ์ˆ˜ ๋ชฉ ๊ธˆ ํ† 
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
๊ธ€ ๋ณด๊ด€ํ•จ