jw1010110
@jw1010110
Reviews Written
2
Average Rating
5.0
Posts
Q&A
@StepScope ๋๋ @JobScope์ JobOperator
@Configuration class TestConfig( private val jobOperator: JobOperator, private val dataSource: DataSource, private val jobRepository: JobRepository, private val transactionManager: PlatformTransactionManager, ) { companion object { private const val CHUNK_SIZE = 200 } private val logger = KotlinLogging.logger {} @Scheduled(cron = "*/30 * * * * *") fun runtestJob() { val jobParameters = JobParametersBuilder() .addString("startTime", LocalDateTime.now().toString()) .toJobParameters() jobOperator.start(testJob(),jobParameters) } @Bean fun testJob(): Job = JobBuilder("testJob",jobRepository) .start(testStep()) .build() @Bean fun testStep(): Step = StepBuilder("testStep", jobRepository) .chunk(CHUNK_SIZE) .transactionManager(transactionManager) .reader(testReader()) .writer(testWriter()) .build() @Bean @StepScope fun testReader(): JdbcPagingItemReader = JdbcPagingItemReaderBuilder() .name("testReader") .dataSource(dataSource) .pageSize(CHUNK_SIZE) .selectClause("select img_name, pk") .fromClause("from card_img") .sortKeys(mapOf("pk" to Order.ASCENDING)) .rowMapper { rs, _ -> rs.getString("img_name") } .build() @Bean @StepScope fun testWriter(): ItemWriter = ItemWriter { chunk -> logger.info { "${chunk.items.size}๊ฐ ์ ๋ฌ๋ฐ์์ต๋๋ค." } } }์ด ์ฝ๋๋ฅผ ์คํํ๊ณ ๋๋ 30์ด๋ง๋ค x๊ฐ ์ ๋ฌ๋ฐ์์ต๋๋ค. ๋ผ๋ ๋ก๊ทธ๊ฐ ๋จ๊ธธ ๊ธฐ๋ํ๋ค.ํ์ง๋ง ๋ก๊ทธ๋ ์๋์ ๊ฐ์ด ์ต์ด 1ํ๋ง ๋ก๊ทธ๊ฐ ๋จ๋๋ค. ์ด์ ๋ฅผ ๋ชจ๋ฅด๊ฒ ๋ค,,! ํ๋ฃจ์ข ์ผ ์ฝ์ง์ค์ด๋ค..2026-01-04T19:49:30.143+09:00 INFO 98079 --- [ cached-async-1] o.s.b.c.l.s.TaskExecutorJobLauncher : Job: [SimpleJob: [name=testJob]] launched with the following parameters: [{JobParameter{name='startTime', value=2026-01-04T19:49:30.024757, type=class java.lang.String, identifying=true}}] 2026-01-04T19:49:30.205+09:00 INFO 98079 --- [ cached-async-1] o.s.batch.core.job.SimpleStepHandler : Executing step: [testStep] 2026-01-04T19:49:30.224+09:00 INFO 98079 --- [ cached-async-1] com.clip.batch.fcm.TestConfig : 15๊ฐ ์ ๋ฌ๋ฐ์์ต๋๋ค. 2026-01-04T19:49:30.231+09:00 INFO 98079 --- [ cached-async-1] o.s.batch.core.step.AbstractStep : Step: [testStep] executed in 24ms 2026-01-04T19:49:30.259+09:00 INFO 98079 --- [ cached-async-1] o.s.b.c.l.s.TaskExecutorJobLauncher : Job: [SimpleJob: [name=testJob]] completed with the following parameters: [{JobParameter{name='startTime', value=2026-01-04T19:49:30.024757, type=class java.lang.String, identifying=true}}] and the following status: [COMPLETED] in 100ms 2026-01-04T19:50:00.050+09:00 INFO 98079 --- [ cached-async-1] o.s.b.c.l.s.TaskExecutorJobLauncher : Job: [SimpleJob: [name=testJob]] launched with the following parameters: [{JobParameter{name='startTime', value=2026-01-04T19:50:00.006744, type=class java.lang.String, identifying=true}}] 2026-01-04T19:50:00.065+09:00 INFO 98079 --- [ cached-async-1] o.s.batch.core.job.SimpleStepHandler : Executing step: [testStep] 2026-01-04T19:50:00.069+09:00 INFO 98079 --- [ cached-async-1] o.s.batch.core.step.AbstractStep : Step: [testStep] executed in 4ms 2026-01-04T19:50:00.089+09:00 INFO 98079 --- [ cached-async-1] o.s.b.c.l.s.TaskExecutorJobLauncher : Job: [SimpleJob: [name=testJob]] completed with the following parameters: [{JobParameter{name='startTime', value=2026-01-04T19:50:00.006744, type=class java.lang.String, identifying=true}}] and the following status: [COMPLETED] in 31ms
- 1
- 5
- 127
Q&A
@StepScope ๋๋ @JobScope์ JobOperator
ํ๋ผ๋ฏธํฐ ์ ์ ์ ๋ฌ ํ์ธ ํ๊ณ , ์ก์ด ์ ์ ์คํ๋ ๊ฒ๋ ํ์ธ ํ์ด!
- 1
- 5
- 127
Q&A
@StepScope ๋๋ @JobScope์ JobOperator
@Configuration class SampleScheduler( private val jobOperator: JobOperator, private val sampleSchedulerContentService: SampleSchedulerContentService, private val dataSource: DataSource, private val jobRepository: JobRepository, private val transactionManager: PlatformTransactionManager, private val jobRegistry: JobRegistry, ) { companion object { private const val CHUNK_SIZE = 200 } private val logger = KotlinLogging.logger {} @Scheduled(cron = "0 0 19,22 * * *") fun runSampleJob() { val hour = LocalDateTime.now().hour val content = when (hour) { 19 -> sampleSchedulerContentService.findFirstSchedulerContent() 22 -> sampleSchedulerContentService.findSecondSchedulerContent() else -> throw IllegalArgumentException("Invalid hour for FCM scheduling") } val jobParameters = JobParametersBuilder() .addString("title", content.title) .addString("content", content.content) .addString("startTime", LocalDateTime.now().toString()) .toJobParameters() val job = jobRegistry.getJob("sampleJob") ?: throw IllegalStateException("Job not found: sampleJob") jobOperator.start(job, jobParameters) } @Bean fun sampleJob(sampleStep: Step): Job = JobBuilder("sampleJob",jobRepository) .start(sampleStep) .build() @Bean fun sampleStep( sampleReader: JdbcPagingItemReader, sampleWriter: ItemWriter, jdbcTemplate: JdbcTemplate ): Step = StepBuilder("sampleStep", jobRepository) .chunk(CHUNK_SIZE) .transactionManager(transactionManager) .listener(object : StepExecutionListener { override fun beforeStep(se: StepExecution) { val cnt = jdbcTemplate.queryForObject( "select count(*) from member where is_allow_notify = true and firebase_token is not null", Long::class.java ) logger.info { "PRE-CHECK count=$cnt" } } override fun afterStep(se: StepExecution): ExitStatus { logger.info { "readCount=${se.readCount}, writeCount=${se.writeCount}, commitCount=${se.commitCount}" } return se.exitStatus } }) .reader(fcmReader) .writer(fcmWriter) .build() @Bean @StepScope fun sampleReader(): JdbcPagingItemReader { val reader = JdbcPagingItemReaderBuilder() .name("sampleReader") .dataSource(dataSource) .pageSize(CHUNK_SIZE) .selectClause("select firebase_token, pk") .fromClause("from member") .whereClause("is_allow_notify = true and firebase_token is not null") .sortKeys(mapOf("pk" to Order.ASCENDING)) .rowMapper { rs, _ -> rs.getString("firebase_token") } .build() logger.info { "sampleReader bean created: " + System.identityHashCode(reader) } return reader } @Bean @StepScope fun sampleWriter( @Value("#{jobParameters['title']}") title: String?, @Value("#{jobParameters['content']}") content: String?, ): ItemWriter { val itemWriter = ItemWriter { chunk -> logger.info { "${chunk.items.size}๊ฐ์ fcmToken์ ๋์์ผ๋ก multicastFcm ๋น๋๊ธฐ์ฒ๋ฆฌ ํ์์ต๋๋ค." } } logger.info { "sampleWriter bean created: " + System.identityHashCode(itemWriter) } return itemWriter } }ํ ์ ์ฝ๋์ฒ๋ผ ๋๋ฆฌ๋ฉด ์ฒ์ 1ํ๋ ๋ฆฌ๋์์ ์ฟผ๋ฆฌ ์กฐ๊ฑด์ ํด๋นํ๋ ๋งํผ ๋ ์ฝ๋๋ฅผ ์ฝ์ด์ค๊ณ writer๊น์ง ์ ๋๊ฑฐ๋ ? ๊ทผ๋ฐ 2๋ฒ์งธ ์คํ๋ถํฐ reader์์ 0๊ฐ๋ฅผ ์ฝ์ด์ค๋ค? ๊ทธ๋ฌ๋๊น ๋น์ฐํ writer๋ ๋์ ์ํ๊ณ ,,reader ๋น๋ ์คํญ๋ง๋ค ์๋ก ์ ์์ฑ๋๋ ๊ฑธ ํ์ธํ๋๋ฐ ์ ์คํํ๋ฉด 0๊ฐ ์ฝ๊ณ ๋๋ด๋ฒ๋ฆด๊น,,!?๋ฆฌ์ค๋์์ ๋์ ๋์ฝ๋๊ฐ ์ ์กด์ฌํ๋ ๊ฒ๋ ํ์ธํ์ด!
- 1
- 5
- 127
Q&A
Batch6: jobOperator.startNextInstance() throws UnexpectedJobExecutionException
@EnableJdbcJobRepository๋ฅผ ๋ฉ์ธ ์ดํ๋ฆฌ์ผ์ด์ ํด๋์ค์ ์ถ๊ฐํ๊ณ ๋ชจ๋ ๊ฒ์ด ํด๊ฒฐ๋์๋ค..์ธํ๋ฐ์ ๋ํ ๋ฐฐ์น ๋ง์คํฐ kill9ํ๋ ์์ํ์ง ๋ชปํ ์ ๋์ ๊ธฐ์ด์ ์ธ ์ค์๋ฅผ ํด์ ํ์ ์๊ฐ์ ๋นผ์์ ์ ,, ๊น์ด ์ฌ์ฃํ๋ค.๋๋ถ์ ๊ณต์ ๋ง์ด๊ทธ๋ ์ด์ ๋ฌธ์๋ฅผ ๋ค์ ์ฝ๋ค๊ฐ ๋ฐ๊ฒฌํ๋ค.๊ณง ์ธ์์ผ๋ก ๋์ฌ ๋ฐฐ์น6 ๊ฐ์ ๊ธฐ๋ค๋ฆฌ๊ณ ์๊ฒ ๋ค.๊ณ ๋ง๋ค!!
- 1
- 5
- 104
Q&A
Batch6: jobOperator.startNextInstance() throws UnexpectedJobExecutionException
ํค์ด ๋ด, ๋๋ ์ด๋ฏธ ๋๊ฐ ์๋ ค์ค ๋ฐฉ๋ฒ์ gpt์๊ฒ ์ ๋ฌ ๋ฐ์๋ดค๋ค. ๋๊ฐ ๋งํ ๋ฉ์๋๋ ์ด๋ฏธ ์ง์ ์ข ๋ฃ๋ค.๋๋ ๊ทธ์ ๊ธฐ๋ค๋ฆฐ๋ค. kill9,,,,
- 1
- 5
- 104




