๊ฐ์
์คํ๋ง ํ๋ ์์ํฌ์์ ์ ๊ณตํ๋ @Scheduled ์ด๋ ธํ ์ด์ ์ ๋ฉ์๋์ ์ค์ผ์ค๋ง ๊ธฐ๋ฅ์ ๋ถ์ฌํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก @Scheduled ์ด๋ ธํ ์ด์ ๋ง์ ์ฌ์ฉํ๋ฉด ์คํ๋ง์ ๋จ์ผ ์ค๋ ๋์์ ์ค์ผ์ค๋ง ์์ ๋ค์ ์์ฐจ์ ์ผ๋ก ์ฒ๋ฆฌํ๋๋ฐ, ์ด๋ ํ๋์ ์ค์ผ์ค๋ง ์์ ์ด ์๋ฃ๋์ด์ผ๋ง ๋ค์ ์ค์ผ์ค๋ง ์์ ์ด ์คํ๋ ์ ์๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
๋ฐ๋ผ์ ๋ถ๊ฐ์ ์ธ ์ค์ ์์ด ์ฌ๋ฌ ๊ฐ์ ์ค์ผ์ค๋ฌ๋ฅผ ์์ฑํ๋ฉด, ์ผ๋ถ ์์ ์ด ์์์น ๋ชปํ ์๊ฐ์ ๋์ํ ์ ์์ต๋๋ค.
์์ ์ํฉ์ ํ๋ฒ ๋ณด๊ฒ ์ต๋๋ค.
@Configuration @EnableScheduling public class ScheduledTasks { private final Logger log = LoggerFactory.getLogger(ScheduledTasks.class); @Scheduled(fixedRate = 1000) // 1์ด๋ง๋ค taskA๋ฅผ ์คํํฉ๋๋ค. public void taskA() throws InterruptedException { Thread.sleep(10000); // 10์ด ๋์ ์ผ์ ์ค๋จํฉ๋๋ค. log.info("taskA - {} - {}", LocalDateTime.now(), Thread.currentThread().getName()); } @Scheduled(fixedRate = 1000) // 1์ด๋ง๋ค taskB๋ฅผ ์คํํฉ๋๋ค. public void taskB() { // taskB์ ๋ก์ง์ ์คํํฉ๋๋ค. log.info("taskB - {} - {}", LocalDateTime.now(), Thread.currentThread().getName()); }

์์ ์์์์ taskA์ taskB๋ ๊ฐ๊ฐ 1์ด๋ง๋ค ์คํ๋๋๋ก ์ค์ ๋์ด ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์์๊ณผ ๋ฌ๋ฆฌ ์ค์ ๋ก ๋ก๊ทธ๋ฅผ ํ์ธํด ๋ณด๋ฉด, taskB๊ฐ 10์ด์ ํ ๋ฒ๋ง ์คํ๋๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
์ด๋ @Scheduled ์ด๋ ธํ ์ด์ ์ ๊ธฐ๋ณธ ์ค์ ์ด ๋จ์ผ ์ค๋ ๋์์ ์์ ์ ์ํํ๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ด์ ๋ฐ๋ผ, taskA์ taskB๋ ๋์ผํ ์ค๋ ๋์์ ์์ฐจ์ ์ผ๋ก ์คํ๋๋ฉฐ, taskA๋ 10์ด ๋์ ์ผ์ ์ค๋จ๋๋ฏ๋ก, taskB๋ taskA์ ์ํ์ด ๋๋ ๋๊น์ง ๊ธฐ๋ค๋ ค์ผ ํฉ๋๋ค. ์ค์ ๋ก ๋ก๊ทธ์์ 'scheduling-1'์ด๋ผ๋ ๋์ผํ ์ค๋ ๋์์ ๋ ์์ ์ด ์คํ๋๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์๋ ๋ถ๊ฐ์ ์ธ ์ค์ ์ด ํ์ํ๋ฐ, ํฌ๊ฒ ๋ค์๊ณผ ๊ฐ์ด ์ธ ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์กด์ฌํฉ๋๋ค.
- Async ์ฒ๋ฆฌ
- SchedulingConfigurer ๊ตฌํ
- TaskScheduler ๋น ๋ฑ๋ก
1. Async ์ฒ๋ฆฌ
์คํ๋ง์ @Async ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ๋ฉด ๋ฉ์๋๊ฐ ๋ณ๋์ ์ค๋ ๋์์ ๋น๋๊ธฐ์ ์ผ๋ก ์คํ๋ฉ๋๋ค. ์ด๋ฅผ ํตํด ์ฌ๋ฌ ์์ ๋ค์ ๋์์ ์ฒ๋ฆฌํ ์ ์๊ฒ ๋ฉ๋๋ค.
@Configuration @EnableAsync @EnableScheduling public class ScheduledTasks { private final Logger log = LoggerFactory.getLogger(ScheduledTasks.class); @Async @Scheduled(fixedRate = 1000) public void taskA() throws InterruptedException { Thread.sleep(10000); log.info("taskA - {} - {}", LocalDateTime.now(), Thread.currentThread().getName()); } @Async @Scheduled(fixedRate = 1000) public void taskB() { log.info("taskB - {} - {}", LocalDateTime.now(), Thread.currentThread().getName()); } }

์์ ์ฝ๋์์, taskA์ taskB๋ ๊ฐ๊ฐ 1์ด๋ง๋ค ๋ณ๋์ ์ค๋ ๋์์ ๋น๋๊ธฐ๋ก ์คํ๋๋๋ก ์ค์ ๋์ด ์์ต๋๋ค. ์ด๋ ๊ฒ ์ค์ ํ๋ฉด taskA์ ์คํ์ด taskB์ ์ํฅ์ ์ฃผ์ง ์๊ฒ ๋ฉ๋๋ค. ์คํ ๋ก๊ทธ๋ฅผ ํ์ธํด ๋ณด๋ฉด, ์ค์ ๋ก taskA์ taskB๊ฐ ๊ฐ๊ฐ 1์ด๋ง๋ค ๋ ๋ฆฝ์ ์ผ๋ก ๋์ํ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
์ด๋ @Async ์ด๋
ธํ
์ด์
์ ๊ธฐ๋ณธ ์ค์ ์ด SimpleAsyncTaskExecutor๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์
๋๋ค. ํนํ taskA์ ๊ฒฝ์ฐ ์ด์ ์ค์ ์์๋ 10์ด ๋์ ์ผ์ ์ค๋จ๋์์ง๋ง, ์ด๋ฒ ์ค์ ์์๋ 1์ด๋ง๋ค ์๋ก์ด ์ค๋ ๋์์ ๋
๋ฆฝ์ ์ผ๋ก ์ํ๋๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค. ์ด๋ ๊ฒ ๋น๋๊ธฐ๋ก ์ํํ๋ฉด ๋ณ๋์ ์ค๋ ๋์์ ๋
๋ฆฝ์ ์ผ๋ก ์์
์ ์ํํ๋ฏ๋ก, ํ ์์
์ ์ง์ฐ์ด ๋ค๋ฅธ ์์
์ ์ํฅ์ ๋ฏธ์น๋ ๊ฒ์ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
2. SchedulingConfigurer ๊ตฌํ
SchedulingConfigurer ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ฉด, ์ค์ผ์ค๋ฌ์ ๋์์ ๋์ฑ ์ธ๋ถ์ ์ผ๋ก ์ ์ดํ ์ ์์ต๋๋ค. ์ด๋ฅผ ํตํด ์ค์ผ์ค๋ฌ๊ฐ ์ฌ์ฉํ๋ ์ค๋ ๋ ํ์ ํฌ๊ธฐ๋ฅผ ์กฐ์ ํ๊ฑฐ๋ ์ค๋ ๋์ ์ด๋ฆ์ ๋ณ๊ฒฝํ๋ ๋ฑ์ ์์ ์ ์ํํ ์ ์์ต๋๋ค.
@Configuration @EnableScheduling public class SchedulerConfig implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler(); threadPoolTaskScheduler.setPoolSize(10); threadPoolTaskScheduler.setThreadNamePrefix("my-scheduler-"); threadPoolTaskScheduler.initialize(); taskRegistrar.setTaskScheduler(threadPoolTaskScheduler); } }
์ ์์์์๋ SchedulingConfigurer ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ SchedulerConfig ํด๋์ค๊ฐ ์ค๋ ๋ ํ์ ํฌ๊ธฐ๋ฅผ 10์ผ๋ก ์ค์ ํ๊ณ , ์ค๋ ๋ ์ด๋ฆ์ ์ ๋์ฌ๋ฅผ "my-scheduler-"๋ก ์ค์ ํ๊ณ ์์ต๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด, ์ค์ผ์ค๋ง ์์ ์ "my-scheduler-" ์ ๋์ฌ๋ฅผ ๊ฐ์ง 10๊ฐ์ ์ค๋ ๋์์ ๋์์ ์ฒ๋ฆฌ๋ ์ ์๊ฒ ๋ฉ๋๋ค.

์คํ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด taskA์ taskB๊ฐ ๊ฐ๊ฐ ๋ณ๋์ ์ค๋ ๋์์ ์ํ๋๋ ๊ฒ์ ์ ์ ์์ต๋๋ค. ๋ํ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ ๋์๋ ๋ฌ๋ฆฌ taskA์ ํ ๋ฒ์ ์คํ์ด ๋๋์ผ ๊ทธ๋ค์ taskA์ ์คํ์ด ์์๋๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
์ด๋ฅผ ํตํด, ๋์ผํ ์์
์ ๋ํด์๋ ์์ฐจ์ ์ธ ์คํ์ ๋ณด์ฅํ๋ฉด์๋, ๋ค๋ฅธ ์์
๋ค์ ๋ํด์๋ ๋ณ๋ ฌ์ ์ธ ์คํ์ ๊ฐ๋ฅํ๊ฒ ํ๋ ์ค์ผ์ค๋ง ์ค์ ์ ๊ตฌ์ฑํ ์ ์์ต๋๋ค.
3. TaskScheduler ๋น ๋ฑ๋ก
TaskScheduler๋ฅผ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํ๋ ๋ฐฉ๋ฒ์ ์ค์ ๋ฐฉ์์ด ๊ฐ๋จํ๋ค๋ ์ฅ์ ์ด ์์ต๋๋ค.
์ด ๋ฐฉ๋ฒ๋ SchedulingConfigurer์ ๊ตฌํํ๋ ๊ฒ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ์ค์ผ์ค๋ง ๊ธฐ๋ฅ์ ํ์ฑํํ๊ณ , ์ค๋ ๋ ํ์ ํฌ๊ธฐ์ ์ค๋ ๋ ์ด๋ฆ์ ์ ๋์ฌ๋ฅผ ์ค์ ํ๋ ๊ฒ์ ๋์ผํฉ๋๋ค. ํ์ง๋ง ์ค์ผ์ค๋ง ์ค์ ์ ์คํ๋ง ์ปจํ ์ด๋์ ์์ํ์ฌ ์๋์ผ๋ก ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
@Configuration @EnableScheduling public class SchedulerConfig { @Bean public TaskScheduler taskScheduler() { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setPoolSize(10); scheduler.setThreadNamePrefix("my-scheduler-"); scheduler.initialize(); return scheduler; } }
์ ์ฝ๋์์๋ ThreadPoolTaskScheduler๋ฅผ ์์ฑํ๊ณ ์ค๋ ๋ ํ์ ํฌ๊ธฐ๋ฅผ 10์ผ๋ก ์ค์ ํ๋ฉฐ, ์ค๋ ๋ ์ด๋ฆ์ ์ ๋์ฌ๋ฅผ "my-scheduler-"๋ก ์ค์ ํ ํ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํ๊ณ ์์ต๋๋ค. ์ด ์ค์ ์ SchedulingConfigurer ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ๊ณผ ๋์ผํ ๊ฒฐ๊ณผ๋ฅผ ์ ๊ณตํ์ง๋ง, ์คํ๋ง ์ปจํ ์ด๋๊ฐ ์ค์ผ์ค๋ง ์ค์ ์ ์๋์ผ๋ก ์ฒ๋ฆฌํ๋ฏ๋ก ๋ณ๋์ ์ค์ ์์ด๋ ์ฌ๋ฌ ์ค์ผ์ค๋ง ์์ ์ ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
์ฌ๊ธฐ์ "๋ณ๋์ ์ค์ "์ด๋, SchedulingConfigurer๋ฅผ ๊ตฌํํ๋ ๋ฐฉ์์์ ํ์ํ configureTasks ๋ฉ์๋๋ฅผ ์ง์ ๊ตฌํํ๋ ๋ฑ์ ์์ ์ ์๋ฏธํฉ๋๋ค. TaskScheduler ๋น ๋ฑ๋ก ๋ฐฉ์์์๋ ์ด๋ฐ ์ถ๊ฐ์ ์ธ ์์ ์์ด๋ ์คํ๋ง์ด ์ค์ผ์ค๋ฌ๋ฅผ ์๋์ผ๋ก ๊ด๋ฆฌํ๊ฒ ๋ฉ๋๋ค.

์คํ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ๋ฉด, SchedulingConfigurer๋ฅผ ๊ตฌํํ์ ๋์ ๋์ผํ ๊ฒฐ๊ณผ๋ฅผ ๋ํ๋ด๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
์ ๋ฆฌ
์คํ๋ง์ @Scheduled ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ๋ฉด ๋ฉ์๋์ ์ค์ผ์ค๋ง ๊ธฐ๋ฅ์ ๋ถ์ฌํ ์ ์์ง๋ง ๊ธฐ๋ณธ ์ค์ ์ผ๋ก๋ ๋ชจ๋ ์์ ์ด ํ ์ค๋ ๋์์ ์์ฐจ์ ์ผ๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค. ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด Async ์ฒ๋ฆฌ, SchedulingConfigurer ๊ตฌํ, TaskScheduler ๋น ๋ฑ๋ก ๋ฑ์ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ์ฌ ์ค์ผ์ค๋ง ๋์์ ์ธ๋ถ์ ์ผ๋ก ์ ์ดํ ์ ์์ต๋๋ค. ์ด๋ฅผ ํตํด ์ฌ๋ฌ ์์ ๋ค์ ๋์์ ์ฒ๋ฆฌํ๊ฑฐ๋, ์ค์ผ์ค๋ง ์ค์ ์ ์๋์ผ๋ก ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
'BackEnd๐ฑ > Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Bucket4j๋ก ํธ๋ํฝ ์ ํํ๊ธฐ(Redis & MariaDB) (14) | 2023.12.03 |
---|---|
ShedLock์ผ๋ก ๋ค์ค ์ธ์คํด์ค ํ๊ฒฝ์์ ๋จ์ผ ์ค์ผ์ค๋ฌ ๋์ ๋ณด์ฅํ๊ธฐ (2) | 2023.11.24 |
default method๋ก JpaRepository ์ข ๋ ์ฐ์ํ๊ฒ ์จ๋ณด๊ธฐ (0) | 2023.11.16 |
ArchUnit์ผ๋ก ์ํคํ ์ฒ ๊ฒ์ฌํ๊ธฐ (0) | 2023.10.28 |
LocalStack์ ํ์ฉํ AWS S3 ํ ์คํธ ํ๊ฒฝ ๊ตฌ์ถํ๊ธฐ (2) | 2023.10.22 |
TestContainer๋ก ํตํฉ ํ ์คํธ ํ๊ฒฝ ๊ตฌ์ถํ๊ธฐ (3) | 2023.10.15 |
๋๊ธ