From bfaf0ec508469d73570495e07dbb81f8a7093978 Mon Sep 17 00:00:00 2001 From: ingpyo Date: Sun, 10 Mar 2024 10:40:55 +0900 Subject: [PATCH 01/16] =?UTF-8?q?feat:=20Batch=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EB=B0=8F=20user=EC=97=94=ED=8B=B0=ED=8B=B0=20=EC=9E=AC?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doochul/build.gradle | 5 ++-- .../java/org/doochul/config/AppConfig.java | 17 ------------- .../java/org/doochul/config/AsyncConfig.java | 23 ++++++++++++++++++ .../java/org/doochul/config/BatchConfig.java | 19 +++++++++++++++ .../org/doochul/domain/lesson/Lesson.java | 24 +++++++++++++++++++ .../doochul/domain/membership/MemberShip.java | 8 ++++++- .../org/doochul/domain/product/Product.java | 8 +++++++ .../domain/product/ProductRepository.java | 2 +- .../java/org/doochul/domain/user/User.java | 15 +++++++++++- .../main/java/org/doochul/service/Letter.java | 11 ++++----- .../src/main/resources/application.properties | 9 +++++-- 11 files changed, 111 insertions(+), 30 deletions(-) create mode 100644 doochul/src/main/java/org/doochul/config/AsyncConfig.java create mode 100644 doochul/src/main/java/org/doochul/config/BatchConfig.java diff --git a/doochul/build.gradle b/doochul/build.gradle index 81f9f50..bd981b9 100644 --- a/doochul/build.gradle +++ b/doochul/build.gradle @@ -26,13 +26,14 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-webflux' implementation 'org.springframework.boot:spring-boot-starter-data-redis' - + implementation 'org.springframework.boot:spring-boot-starter-batch' implementation 'com.google.firebase:firebase-admin:9.2.0' - runtimeOnly 'mysql:mysql-connector-java' + runtimeOnly 'mysql:mysql-connector-java:8.0.28' runtimeOnly 'com.h2database:h2' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.batch:spring-batch-test' testImplementation 'org.springframework.boot:spring-boot-starter-test' } diff --git a/doochul/src/main/java/org/doochul/config/AppConfig.java b/doochul/src/main/java/org/doochul/config/AppConfig.java index 7476aaa..502f671 100644 --- a/doochul/src/main/java/org/doochul/config/AppConfig.java +++ b/doochul/src/main/java/org/doochul/config/AppConfig.java @@ -3,9 +3,6 @@ import java.time.Clock; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.TaskScheduler; -import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; -import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; @Configuration public class AppConfig { @@ -14,18 +11,4 @@ public class AppConfig { public Clock clock() { return Clock.systemDefaultZone(); } - - @Bean - public TaskScheduler taskScheduler() { - ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); - taskScheduler.setPoolSize(10); - return taskScheduler; - } - - @Bean - public ThreadPoolTaskScheduler taskScheduler() { - ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); - scheduler.setPoolSize(2); - return scheduler; - } } diff --git a/doochul/src/main/java/org/doochul/config/AsyncConfig.java b/doochul/src/main/java/org/doochul/config/AsyncConfig.java new file mode 100644 index 0000000..82db621 --- /dev/null +++ b/doochul/src/main/java/org/doochul/config/AsyncConfig.java @@ -0,0 +1,23 @@ +package org.doochul.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.Executor; + +@EnableAsync +@Configuration +public class AsyncConfig { + + @Bean + public Executor taskExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(8); + executor.setWaitForTasksToCompleteOnShutdown(true); + executor.setAwaitTerminationSeconds(60); + executor.initialize(); + return executor; + } +} \ No newline at end of file diff --git a/doochul/src/main/java/org/doochul/config/BatchConfig.java b/doochul/src/main/java/org/doochul/config/BatchConfig.java new file mode 100644 index 0000000..17189e7 --- /dev/null +++ b/doochul/src/main/java/org/doochul/config/BatchConfig.java @@ -0,0 +1,19 @@ +package org.doochul.config; + +import org.springframework.batch.core.configuration.JobRegistry; +import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; +import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@EnableBatchProcessing +@Configuration +public class BatchConfig { + + @Bean + public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor(JobRegistry jobRegistry) { + JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor = new JobRegistryBeanPostProcessor(); + jobRegistryBeanPostProcessor.setJobRegistry(jobRegistry); + return jobRegistryBeanPostProcessor; + } +} diff --git a/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java b/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java index aca87ee..13542b1 100644 --- a/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java +++ b/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java @@ -12,6 +12,7 @@ import lombok.NoArgsConstructor; import org.doochul.domain.BaseEntity; import org.doochul.domain.membership.MemberShip; +import org.doochul.domain.user.User; @Entity @Getter @@ -26,9 +27,32 @@ public class Lesson extends BaseEntity { @JoinColumn(name = "membership_id") private MemberShip memberShip; + @ManyToOne + @JoinColumn(name = "student_id") + private User student; + + @ManyToOne + @JoinColumn(name = "teacher_id") + private User teacher; + private LocalDateTime startedAt; private LocalDateTime endedAt; private String record; + + public Lesson( + final MemberShip memberShip, + final User student, + final User teacher, + final LocalDateTime startedAt, + final LocalDateTime endedAt + ) { + this.memberShip = memberShip; + this.student = student; + this.teacher = teacher; + this.startedAt = startedAt; + this.endedAt = endedAt; + this.record = null; + } } diff --git a/doochul/src/main/java/org/doochul/domain/membership/MemberShip.java b/doochul/src/main/java/org/doochul/domain/membership/MemberShip.java index 382e41b..84d6d74 100644 --- a/doochul/src/main/java/org/doochul/domain/membership/MemberShip.java +++ b/doochul/src/main/java/org/doochul/domain/membership/MemberShip.java @@ -23,7 +23,7 @@ public class MemberShip extends BaseEntity { private Long id; @ManyToOne - @JoinColumn(name = "user_id") + @JoinColumn(name = "student_id") private User student; @ManyToOne @@ -32,6 +32,12 @@ public class MemberShip extends BaseEntity { private Integer remainingCount; + public MemberShip(final User student, final Product product, final Integer remainingCount) { + this.student = student; + this.product = product; + this.remainingCount = remainingCount; + } + public void decreasedCount() { validateMinRemainingCount(); remainingCount -= 1; diff --git a/doochul/src/main/java/org/doochul/domain/product/Product.java b/doochul/src/main/java/org/doochul/domain/product/Product.java index f9ba1b5..6641b3f 100644 --- a/doochul/src/main/java/org/doochul/domain/product/Product.java +++ b/doochul/src/main/java/org/doochul/domain/product/Product.java @@ -33,4 +33,12 @@ public class Product extends BaseEntity { private User teacher; private Integer count; + + + public Product(final String name, final ProductType type, final User teacher, final Integer count) { + this.name = name; + this.type = type; + this.teacher = teacher; + this.count = count; + } } diff --git a/doochul/src/main/java/org/doochul/domain/product/ProductRepository.java b/doochul/src/main/java/org/doochul/domain/product/ProductRepository.java index 1cb880e..531d980 100644 --- a/doochul/src/main/java/org/doochul/domain/product/ProductRepository.java +++ b/doochul/src/main/java/org/doochul/domain/product/ProductRepository.java @@ -5,6 +5,6 @@ import org.springframework.stereotype.Repository; @Repository -public interface ProductRepository extends JpaRepository { +public interface ProductRepository extends JpaRepository { List findByUserId(Long userId); } diff --git a/doochul/src/main/java/org/doochul/domain/user/User.java b/doochul/src/main/java/org/doochul/domain/user/User.java index 39391b8..0af8242 100644 --- a/doochul/src/main/java/org/doochul/domain/user/User.java +++ b/doochul/src/main/java/org/doochul/domain/user/User.java @@ -11,7 +11,6 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; -import lombok.RequiredArgsConstructor; import org.doochul.domain.BaseEntity; @Entity @@ -36,4 +35,18 @@ public class User extends BaseEntity { @Enumerated(EnumType.STRING) private Identity identity; + + public User( + final String name, + final String deviceToken, + final String passWord, + final Gender gender, + final Identity identity + ) { + this.name = name; + this.deviceToken = deviceToken; + this.passWord = passWord; + this.gender = gender; + this.identity = identity; + } } diff --git a/doochul/src/main/java/org/doochul/service/Letter.java b/doochul/src/main/java/org/doochul/service/Letter.java index f18da78..b096ba5 100644 --- a/doochul/src/main/java/org/doochul/service/Letter.java +++ b/doochul/src/main/java/org/doochul/service/Letter.java @@ -1,7 +1,5 @@ package org.doochul.service; -import org.doochul.domain.user.User; - import java.time.LocalDateTime; public record Letter( @@ -10,12 +8,13 @@ public record Letter( String body ) { public static Letter of( - final User student, - final User teacher, + final String studentToken, + final String studentName, + final String teacherName, final LocalDateTime startedAt, final LessonStatus lessonStatus ) { - final String message = lessonStatus.getMessage(student.getName(), startedAt, teacher.getName()); - return new Letter(student.getDeviceToken(), lessonStatus.getTitle(), message); + final String message = lessonStatus.getMessage(studentName, startedAt, teacherName); + return new Letter(studentToken, lessonStatus.getTitle(), message); } } diff --git a/doochul/src/main/resources/application.properties b/doochul/src/main/resources/application.properties index 7365132..afb3b70 100644 --- a/doochul/src/main/resources/application.properties +++ b/doochul/src/main/resources/application.properties @@ -1,4 +1,9 @@ -spring.datasource.url=jdbc:h2:mem:testdb;MODE=MySQL; - +#spring.datasource.url=jdbc:h2:mem:testdb;MODE=MySQL; +spring.datasource.url=jdbc:mysql://localhost:3306/my_database?characterEncoding=UTF-8&serverTimezone=Asia/Seoul +spring.datasource.username= root +spring.datasource.password= 123 +spring.jpa.hibernate.ddl-auto=create +spring.jpa.show-sql=true +spring.batch.jdbc.initialize-schema=always fcm.certification.path=kwakdoochul-bbb43-firebase-adminsdk-oyokf-f075393454.json \ No newline at end of file From ae32fec99365e911446f94a14c916265cf1ee72e Mon Sep 17 00:00:00 2001 From: ingpyo Date: Sun, 10 Mar 2024 10:41:35 +0900 Subject: [PATCH 02/16] =?UTF-8?q?feat:=20Batch=EB=A5=BC=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=B4=20=EC=88=98=EC=97=85=EC=A0=84=20=EB=A6=AC?= =?UTF-8?q?=EB=A7=88=EC=9D=B8=EB=93=9C=20=EC=95=8C=EB=9E=8C=20=EC=8A=A4?= =?UTF-8?q?=EC=BC=80=EC=A4=84=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SandNotificationBeforeClassJobConfig.java | 98 +++++++++++++++++++ .../job/SendNotificationItemWriter.java | 25 +++++ 2 files changed, 123 insertions(+) create mode 100644 doochul/src/main/java/org/doochul/job/SandNotificationBeforeClassJobConfig.java create mode 100644 doochul/src/main/java/org/doochul/job/SendNotificationItemWriter.java diff --git a/doochul/src/main/java/org/doochul/job/SandNotificationBeforeClassJobConfig.java b/doochul/src/main/java/org/doochul/job/SandNotificationBeforeClassJobConfig.java new file mode 100644 index 0000000..2baef24 --- /dev/null +++ b/doochul/src/main/java/org/doochul/job/SandNotificationBeforeClassJobConfig.java @@ -0,0 +1,98 @@ +package org.doochul.job; + +import org.doochul.service.Letter; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.job.builder.JobBuilder; +import org.springframework.batch.core.launch.support.RunIdIncrementer; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.step.builder.StepBuilder; +import org.springframework.batch.item.ItemProcessor; +import org.springframework.batch.item.database.JdbcPagingItemReader; +import org.springframework.batch.item.database.PagingQueryProvider; +import org.springframework.batch.item.database.builder.JdbcPagingItemReaderBuilder; +import org.springframework.batch.item.database.support.SqlPagingQueryProviderFactoryBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.jdbc.core.ColumnMapRowMapper; +import org.springframework.transaction.PlatformTransactionManager; + +import javax.sql.DataSource; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +import static org.doochul.service.LessonStatus.BEFORE_LESSON; + +@Configuration +public class SandNotificationBeforeClassJobConfig { + private static final int CHUNK_SIZE = 10; + + private final DataSource dataSource; + private final SendNotificationItemWriter sendNotificationItemWriter; + + public SandNotificationBeforeClassJobConfig(final DataSource dataSource, final SendNotificationItemWriter sendNotificationItemWriter) { + this.dataSource = dataSource; + this.sendNotificationItemWriter = sendNotificationItemWriter; + } + + @Bean + public Job sendNotificationBeforeClassJob(JobRepository jobRepository, PlatformTransactionManager transactionManager) throws Exception { + return new JobBuilder("sendNotificationBeforeClassJob", jobRepository) + .incrementer(new RunIdIncrementer()) + .start(sendNotificationBeforeClassStep(jobRepository, transactionManager)) + .build(); + } + + @Bean + public Step sendNotificationBeforeClassStep( + JobRepository jobRepository, + PlatformTransactionManager transactionManager + ) throws Exception { + return new StepBuilder("addNotificationStep", jobRepository) + ., Letter>chunk(CHUNK_SIZE, transactionManager) + .reader(addNotificationItemReader()) + .processor(addNotificationItemProcessor()) + .writer(sendNotificationItemWriter) + .taskExecutor(new SimpleAsyncTaskExecutor()) + .build(); + } + + @Bean + public JdbcPagingItemReader> addNotificationItemReader() throws Exception { + Map parameterValues = new HashMap<>(); + parameterValues.put("startedAt", LocalDateTime.now().plusMinutes(10)); + + return new JdbcPagingItemReaderBuilder>() + .name("addNotificationItemReader") + .dataSource(dataSource) + .pageSize(CHUNK_SIZE) + .queryProvider(createQueryProvider()) + .parameterValues(parameterValues) + .rowMapper(new ColumnMapRowMapper()) + .build(); + } + + private PagingQueryProvider createQueryProvider() throws Exception { + SqlPagingQueryProviderFactoryBean queryProvider = new SqlPagingQueryProviderFactoryBean(); + queryProvider.setDataSource(dataSource); + queryProvider.setSelectClause("u.device_token AS student_token, u.name AS student_name, t.name AS teacher_name, l.started_at"); + queryProvider.setFromClause("FROM lesson l JOIN users u ON l.student_id = u.id JOIN users t ON l.teacher_id = t.id"); + queryProvider.setWhereClause("WHERE l.started_at <= :startedAt"); + + return queryProvider.getObject(); + } + + @Bean + public ItemProcessor, Letter> addNotificationItemProcessor() { + return item -> { + String studentToken = (String) item.get("student_token"); + String studentName = (String) item.get("student_name"); + String teacherName = (String) item.get("teacher_name"); + LocalDateTime startedAt = (LocalDateTime) item.get("started_at"); + + return Letter.of(studentToken, studentName, teacherName, startedAt, BEFORE_LESSON); + }; + } +} diff --git a/doochul/src/main/java/org/doochul/job/SendNotificationItemWriter.java b/doochul/src/main/java/org/doochul/job/SendNotificationItemWriter.java new file mode 100644 index 0000000..158f3bc --- /dev/null +++ b/doochul/src/main/java/org/doochul/job/SendNotificationItemWriter.java @@ -0,0 +1,25 @@ +package org.doochul.job; + +import lombok.extern.slf4j.Slf4j; +import org.doochul.service.Letter; +import org.doochul.service.MessageSendManager; +import org.springframework.batch.item.Chunk; +import org.springframework.batch.item.ItemWriter; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class SendNotificationItemWriter implements ItemWriter { + private final MessageSendManager messageSendManager; + + public SendNotificationItemWriter(MessageSendManager messageSendManager) { + this.messageSendManager = messageSendManager; + } + + @Override + public void write(final Chunk letters) { + for (final Letter letter : letters) { + messageSendManager.sendTo(letter); + } + } +} From a8621ff30d8bca926d7f02e76755650863a2ef41 Mon Sep 17 00:00:00 2001 From: ingpyo Date: Sun, 10 Mar 2024 19:41:16 +0900 Subject: [PATCH 03/16] =?UTF-8?q?feat:=20Batch=EB=A5=BC=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=B4=20=EC=88=98=EC=97=85=EC=A0=84=20=EB=A6=AC?= =?UTF-8?q?=EB=A7=88=EC=9D=B8=EB=93=9C=20=EC=95=8C=EB=9E=8C=20=EC=8A=A4?= =?UTF-8?q?=EC=BC=80=EC=A4=84=20=EC=9E=91=EC=84=B1(JPA=20->=20=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=EB=A1=9C=20=EB=B3=80=EA=B2=BD)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...andNotificationBeforeLessonJobConfig.java} | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) rename doochul/src/main/java/org/doochul/job/{SandNotificationBeforeClassJobConfig.java => SandNotificationBeforeLessonJobConfig.java} (78%) diff --git a/doochul/src/main/java/org/doochul/job/SandNotificationBeforeClassJobConfig.java b/doochul/src/main/java/org/doochul/job/SandNotificationBeforeLessonJobConfig.java similarity index 78% rename from doochul/src/main/java/org/doochul/job/SandNotificationBeforeClassJobConfig.java rename to doochul/src/main/java/org/doochul/job/SandNotificationBeforeLessonJobConfig.java index 2baef24..49bafd0 100644 --- a/doochul/src/main/java/org/doochul/job/SandNotificationBeforeClassJobConfig.java +++ b/doochul/src/main/java/org/doochul/job/SandNotificationBeforeLessonJobConfig.java @@ -9,6 +9,7 @@ import org.springframework.batch.core.step.builder.StepBuilder; import org.springframework.batch.item.ItemProcessor; import org.springframework.batch.item.database.JdbcPagingItemReader; +import org.springframework.batch.item.database.Order; import org.springframework.batch.item.database.PagingQueryProvider; import org.springframework.batch.item.database.builder.JdbcPagingItemReaderBuilder; import org.springframework.batch.item.database.support.SqlPagingQueryProviderFactoryBean; @@ -22,31 +23,32 @@ import java.time.LocalDateTime; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import static org.doochul.service.LessonStatus.BEFORE_LESSON; @Configuration -public class SandNotificationBeforeClassJobConfig { +public class SandNotificationBeforeLessonJobConfig { private static final int CHUNK_SIZE = 10; private final DataSource dataSource; private final SendNotificationItemWriter sendNotificationItemWriter; - public SandNotificationBeforeClassJobConfig(final DataSource dataSource, final SendNotificationItemWriter sendNotificationItemWriter) { + public SandNotificationBeforeLessonJobConfig(final DataSource dataSource, final SendNotificationItemWriter sendNotificationItemWriter) { this.dataSource = dataSource; this.sendNotificationItemWriter = sendNotificationItemWriter; } @Bean - public Job sendNotificationBeforeClassJob(JobRepository jobRepository, PlatformTransactionManager transactionManager) throws Exception { - return new JobBuilder("sendNotificationBeforeClassJob", jobRepository) + public Job sandNotificationBeforeLessonJob(JobRepository jobRepository, PlatformTransactionManager transactionManager) throws Exception { + return new JobBuilder("sandNotificationBeforeLessonJob", jobRepository) .incrementer(new RunIdIncrementer()) - .start(sendNotificationBeforeClassStep(jobRepository, transactionManager)) + .start(sendNotificationBeforeLessonStep(jobRepository, transactionManager)) .build(); } @Bean - public Step sendNotificationBeforeClassStep( + public Step sendNotificationBeforeLessonStep( JobRepository jobRepository, PlatformTransactionManager transactionManager ) throws Exception { @@ -77,11 +79,14 @@ public JdbcPagingItemReader> addNotificationItemReader() thr private PagingQueryProvider createQueryProvider() throws Exception { SqlPagingQueryProviderFactoryBean queryProvider = new SqlPagingQueryProviderFactoryBean(); queryProvider.setDataSource(dataSource); - queryProvider.setSelectClause("u.device_token AS student_token, u.name AS student_name, t.name AS teacher_name, l.started_at"); + queryProvider.setSelectClause("SELECT u.device_token AS student_token, u.name AS student_name, t.name AS teacher_name, l.started_at"); queryProvider.setFromClause("FROM lesson l JOIN users u ON l.student_id = u.id JOIN users t ON l.teacher_id = t.id"); queryProvider.setWhereClause("WHERE l.started_at <= :startedAt"); + Map sortKeys = new HashMap<>(1); + sortKeys.put("l.started_at", Order.ASCENDING); - return queryProvider.getObject(); + queryProvider.setSortKeys(sortKeys); + return Optional.ofNullable(queryProvider.getObject()).orElseThrow(IllegalArgumentException::new); } @Bean @@ -91,7 +96,6 @@ public ItemProcessor, Letter> addNotificationItemProcessor() String studentName = (String) item.get("student_name"); String teacherName = (String) item.get("teacher_name"); LocalDateTime startedAt = (LocalDateTime) item.get("started_at"); - return Letter.of(studentToken, studentName, teacherName, startedAt, BEFORE_LESSON); }; } From 91d64c11e55a8e075da3c21be8dbef704266b33f Mon Sep 17 00:00:00 2001 From: ingpyo Date: Sun, 10 Mar 2024 20:27:23 +0900 Subject: [PATCH 04/16] =?UTF-8?q?feat:=20Batch=EB=A5=BC=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=B4=20=EC=88=98=EC=97=85=ED=9B=84=20=EC=95=8C?= =?UTF-8?q?=EB=9E=8C=20=EB=B0=8F=20=EC=9D=B4=EC=9A=A9=EA=B6=8C=20=EA=B0=9C?= =?UTF-8?q?=EC=88=98=20=EC=B0=A8=EA=B0=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SandNotificationAfterLessonJobConfig.java | 103 ++++++++++++++++++ .../job/UpdateRemainingCountJobConfig.java | 52 +++++++++ 2 files changed, 155 insertions(+) create mode 100644 doochul/src/main/java/org/doochul/job/SandNotificationAfterLessonJobConfig.java create mode 100644 doochul/src/main/java/org/doochul/job/UpdateRemainingCountJobConfig.java diff --git a/doochul/src/main/java/org/doochul/job/SandNotificationAfterLessonJobConfig.java b/doochul/src/main/java/org/doochul/job/SandNotificationAfterLessonJobConfig.java new file mode 100644 index 0000000..a089b15 --- /dev/null +++ b/doochul/src/main/java/org/doochul/job/SandNotificationAfterLessonJobConfig.java @@ -0,0 +1,103 @@ +package org.doochul.job; + +import org.doochul.service.Letter; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.job.builder.JobBuilder; +import org.springframework.batch.core.launch.support.RunIdIncrementer; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.step.builder.StepBuilder; +import org.springframework.batch.item.ItemProcessor; +import org.springframework.batch.item.database.JdbcPagingItemReader; +import org.springframework.batch.item.database.Order; +import org.springframework.batch.item.database.PagingQueryProvider; +import org.springframework.batch.item.database.builder.JdbcPagingItemReaderBuilder; +import org.springframework.batch.item.database.support.SqlPagingQueryProviderFactoryBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.jdbc.core.ColumnMapRowMapper; +import org.springframework.transaction.PlatformTransactionManager; + +import javax.sql.DataSource; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import static org.doochul.service.LessonStatus.AFTER_LESSON; + +@Configuration +public class SandNotificationAfterLessonJobConfig { + private static final int CHUNK_SIZE = 10; + + private final DataSource dataSource; + private final SendNotificationItemWriter sendNotificationItemWriter; + + public SandNotificationAfterLessonJobConfig(final DataSource dataSource, final SendNotificationItemWriter sendNotificationItemWriter) { + this.dataSource = dataSource; + this.sendNotificationItemWriter = sendNotificationItemWriter; + } + + @Bean + public Job sandNotificationAfterLessonJob(JobRepository jobRepository, PlatformTransactionManager transactionManager) throws Exception { + return new JobBuilder("sandNotificationAfterLesson", jobRepository) + .incrementer(new RunIdIncrementer()) + .start(sendNotificationBeforeClassStep(jobRepository, transactionManager)) + .build(); + } + + @Bean + public Step sendNotificationBeforeClassStep( + JobRepository jobRepository, + PlatformTransactionManager transactionManager + ) throws Exception { + return new StepBuilder("addNotificationStep", jobRepository) + ., Letter>chunk(CHUNK_SIZE, transactionManager) + .reader(addNotificationItemReader()) + .processor(addNotificationItemProcessor()) + .writer(sendNotificationItemWriter) + .taskExecutor(new SimpleAsyncTaskExecutor()) + .build(); + } + + @Bean + public JdbcPagingItemReader> addNotificationItemReader() throws Exception { + Map parameterValues = new HashMap<>(); + parameterValues.put("endedAt", LocalDateTime.now()); + + return new JdbcPagingItemReaderBuilder>() + .name("addNotificationItemReader") + .dataSource(dataSource) + .pageSize(CHUNK_SIZE) + .queryProvider(createQueryProvider()) + .parameterValues(parameterValues) + .rowMapper(new ColumnMapRowMapper()) + .build(); + } + + private PagingQueryProvider createQueryProvider() throws Exception { + SqlPagingQueryProviderFactoryBean queryProvider = new SqlPagingQueryProviderFactoryBean(); + queryProvider.setDataSource(dataSource); + queryProvider.setSelectClause("SELECT u.device_token AS student_token, u.name AS student_name, t.name AS teacher_name, l.ended_at"); + queryProvider.setFromClause("FROM lesson l JOIN users u ON l.student_id = u.id JOIN users t ON l.teacher_id = t.id"); + queryProvider.setWhereClause("WHERE l.ended_at <= :endedAt"); + + Map sortKeys = new HashMap<>(1); + sortKeys.put("l.ended_at", Order.ASCENDING); + + queryProvider.setSortKeys(sortKeys); + return Optional.ofNullable(queryProvider.getObject()).orElseThrow(IllegalArgumentException::new); + } + + @Bean + public ItemProcessor, Letter> addNotificationItemProcessor() { + return item -> { + String studentToken = (String) item.get("student_token"); + String studentName = (String) item.get("student_name"); + String teacherName = (String) item.get("teacher_name"); + LocalDateTime endedAt = (LocalDateTime) item.get("ended_at"); + return Letter.of(studentToken, studentName, teacherName, endedAt, AFTER_LESSON); + }; + } +} diff --git a/doochul/src/main/java/org/doochul/job/UpdateRemainingCountJobConfig.java b/doochul/src/main/java/org/doochul/job/UpdateRemainingCountJobConfig.java new file mode 100644 index 0000000..e9340f7 --- /dev/null +++ b/doochul/src/main/java/org/doochul/job/UpdateRemainingCountJobConfig.java @@ -0,0 +1,52 @@ +package org.doochul.job; + +import org.springframework.batch.core.Job; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.StepContribution; +import org.springframework.batch.core.job.builder.JobBuilder; +import org.springframework.batch.core.launch.support.RunIdIncrementer; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.scope.context.ChunkContext; +import org.springframework.batch.core.step.builder.StepBuilder; +import org.springframework.batch.core.step.tasklet.Tasklet; +import org.springframework.batch.repeat.RepeatStatus; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.transaction.PlatformTransactionManager; + +import java.time.LocalDateTime; +import java.util.Collections; + +@Configuration +public class UpdateRemainingCountJobConfig { + @Bean + public Step updateRemainingCountStep(JobRepository jobRepository, PlatformTransactionManager transactionManager, JdbcTemplate jdbcTemplate) { + return new StepBuilder("updateRemainingCountStep", jobRepository) + .tasklet(new UpdateRemainingCountTasklet(jdbcTemplate), transactionManager) + .build(); + } + + @Bean + public Job updateRemainingCountJob(JobRepository jobRepository, PlatformTransactionManager transactionManager, JdbcTemplate jdbcTemplate) { + return new JobBuilder("updateRemainingCountJob", jobRepository) + .incrementer(new RunIdIncrementer()) + .start(updateRemainingCountStep(jobRepository, transactionManager, jdbcTemplate)) + .build(); + } + + private static class UpdateRemainingCountTasklet implements Tasklet { + private final JdbcTemplate jdbcTemplate; + + public UpdateRemainingCountTasklet(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + @Override + public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) { + jdbcTemplate.update("UPDATE lesson JOIN member_ship m ON l.membership_id = m.id SET m.remaining_count = m.remaining_count - 1 WHERE l.ended_at <= :endedAt", + Collections.singletonMap("endedAt", LocalDateTime.now())); + return RepeatStatus.FINISHED; + } + } +} From 52af19ff3dd3dd258fb4baa65f75815f588509c2 Mon Sep 17 00:00:00 2001 From: ingpyo Date: Sun, 10 Mar 2024 20:36:52 +0900 Subject: [PATCH 05/16] =?UTF-8?q?feat:=20job=EC=9D=84=20=EC=8B=A4=ED=96=89?= =?UTF-8?q?=EC=8B=9C=ED=82=A4=EB=8A=94=20=EC=8A=A4=EC=BC=80=EC=A4=84?= =?UTF-8?q?=EB=9F=AC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/doochul/job/BatchScheduler.java | 42 +++++++++++++++++++ .../job/UpdateRemainingCountJobConfig.java | 14 +++---- 2 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 doochul/src/main/java/org/doochul/job/BatchScheduler.java diff --git a/doochul/src/main/java/org/doochul/job/BatchScheduler.java b/doochul/src/main/java/org/doochul/job/BatchScheduler.java new file mode 100644 index 0000000..695dc31 --- /dev/null +++ b/doochul/src/main/java/org/doochul/job/BatchScheduler.java @@ -0,0 +1,42 @@ +package org.doochul.job; + +import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.JobParametersBuilder; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Component +public class BatchScheduler { + + private final JobLauncher jobLauncher; + private final Job sandNotificationAfterLessonJob; + private final Job sandNotificationBeforeLessonJob; + private final Job updateRemainingCountJob; + + public BatchScheduler(JobLauncher jobLauncher, + @Qualifier("sandNotificationAfterLessonJob") Job sandNotificationAfterLessonJob, + @Qualifier("sandNotificationBeforeLessonJob") Job sandNotificationBeforeLessonJob, + @Qualifier("updateRemainingCountJob") Job updateRemainingCountJob) { + this.jobLauncher = jobLauncher; + this.sandNotificationAfterLessonJob = sandNotificationAfterLessonJob; + this.sandNotificationBeforeLessonJob = sandNotificationBeforeLessonJob; + this.updateRemainingCountJob = updateRemainingCountJob; + } + + @Scheduled(cron = "0 0/1 * * * *") + public void runJobs() throws Exception { + runJob(sandNotificationAfterLessonJob); + runJob(sandNotificationBeforeLessonJob); + runJob(updateRemainingCountJob); + } + + private void runJob(Job job) throws Exception { + JobParameters parameters = new JobParametersBuilder() + .addString("jobName: ", job.getName() + System.currentTimeMillis()) + .toJobParameters(); + jobLauncher.run(job, parameters); + } +} \ No newline at end of file diff --git a/doochul/src/main/java/org/doochul/job/UpdateRemainingCountJobConfig.java b/doochul/src/main/java/org/doochul/job/UpdateRemainingCountJobConfig.java index e9340f7..f755e79 100644 --- a/doochul/src/main/java/org/doochul/job/UpdateRemainingCountJobConfig.java +++ b/doochul/src/main/java/org/doochul/job/UpdateRemainingCountJobConfig.java @@ -20,13 +20,6 @@ @Configuration public class UpdateRemainingCountJobConfig { - @Bean - public Step updateRemainingCountStep(JobRepository jobRepository, PlatformTransactionManager transactionManager, JdbcTemplate jdbcTemplate) { - return new StepBuilder("updateRemainingCountStep", jobRepository) - .tasklet(new UpdateRemainingCountTasklet(jdbcTemplate), transactionManager) - .build(); - } - @Bean public Job updateRemainingCountJob(JobRepository jobRepository, PlatformTransactionManager transactionManager, JdbcTemplate jdbcTemplate) { return new JobBuilder("updateRemainingCountJob", jobRepository) @@ -35,7 +28,14 @@ public Job updateRemainingCountJob(JobRepository jobRepository, PlatformTransact .build(); } + @Bean + public Step updateRemainingCountStep(JobRepository jobRepository, PlatformTransactionManager transactionManager, JdbcTemplate jdbcTemplate) { + return new StepBuilder("updateRemainingCountStep", jobRepository) + .tasklet(new UpdateRemainingCountTasklet(jdbcTemplate), transactionManager) + .build(); + } private static class UpdateRemainingCountTasklet implements Tasklet { + private final JdbcTemplate jdbcTemplate; public UpdateRemainingCountTasklet(JdbcTemplate jdbcTemplate) { From aee1e2dae2ce012936f55abd27c3fe1250064cbf Mon Sep 17 00:00:00 2001 From: ingpyo Date: Mon, 11 Mar 2024 15:10:32 +0900 Subject: [PATCH 06/16] =?UTF-8?q?feat:=20batch=EB=A1=9C=20=EC=8A=A4?= =?UTF-8?q?=EC=BC=80=EC=A4=84=20=EB=A1=9C=EC=A7=81=20=EC=9D=B4=EB=8F=99=20?= =?UTF-8?q?=EB=B0=8F=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EB=84=A4=EC=9D=B4?= =?UTF-8?q?=EB=B0=8D=20=EC=98=A4=ED=83=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/doochul/application/RedisService.java | 1 - .../java/org/doochul/config/AsyncConfig.java | 2 +- .../org/doochul/domain/product/Product.java | 1 - ...SendNotificationAfterLessonJobConfig.java} | 4 +- ...endNotificationBeforeLessonJobConfig.java} | 4 +- .../doochul/service/NotificationService.java | 77 +++---------------- 6 files changed, 17 insertions(+), 72 deletions(-) rename doochul/src/main/java/org/doochul/job/{SandNotificationAfterLessonJobConfig.java => SendNotificationAfterLessonJobConfig.java} (97%) rename doochul/src/main/java/org/doochul/job/{SandNotificationBeforeLessonJobConfig.java => SendNotificationBeforeLessonJobConfig.java} (97%) diff --git a/doochul/src/main/java/org/doochul/application/RedisService.java b/doochul/src/main/java/org/doochul/application/RedisService.java index 5bd1be3..5c37dc1 100644 --- a/doochul/src/main/java/org/doochul/application/RedisService.java +++ b/doochul/src/main/java/org/doochul/application/RedisService.java @@ -18,7 +18,6 @@ public void delete(final String key) { redisTemplate.delete(key); } - public boolean setNX(final String key, final String value, final Duration duration) { return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, value, duration)); } diff --git a/doochul/src/main/java/org/doochul/config/AsyncConfig.java b/doochul/src/main/java/org/doochul/config/AsyncConfig.java index 82db621..fed0d58 100644 --- a/doochul/src/main/java/org/doochul/config/AsyncConfig.java +++ b/doochul/src/main/java/org/doochul/config/AsyncConfig.java @@ -14,7 +14,7 @@ public class AsyncConfig { @Bean public Executor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); - executor.setCorePoolSize(8); + executor.setCorePoolSize(4); executor.setWaitForTasksToCompleteOnShutdown(true); executor.setAwaitTerminationSeconds(60); executor.initialize(); diff --git a/doochul/src/main/java/org/doochul/domain/product/Product.java b/doochul/src/main/java/org/doochul/domain/product/Product.java index 6641b3f..e43cd98 100644 --- a/doochul/src/main/java/org/doochul/domain/product/Product.java +++ b/doochul/src/main/java/org/doochul/domain/product/Product.java @@ -34,7 +34,6 @@ public class Product extends BaseEntity { private Integer count; - public Product(final String name, final ProductType type, final User teacher, final Integer count) { this.name = name; this.type = type; diff --git a/doochul/src/main/java/org/doochul/job/SandNotificationAfterLessonJobConfig.java b/doochul/src/main/java/org/doochul/job/SendNotificationAfterLessonJobConfig.java similarity index 97% rename from doochul/src/main/java/org/doochul/job/SandNotificationAfterLessonJobConfig.java rename to doochul/src/main/java/org/doochul/job/SendNotificationAfterLessonJobConfig.java index a089b15..c3457e0 100644 --- a/doochul/src/main/java/org/doochul/job/SandNotificationAfterLessonJobConfig.java +++ b/doochul/src/main/java/org/doochul/job/SendNotificationAfterLessonJobConfig.java @@ -28,13 +28,13 @@ import static org.doochul.service.LessonStatus.AFTER_LESSON; @Configuration -public class SandNotificationAfterLessonJobConfig { +public class SendNotificationAfterLessonJobConfig { private static final int CHUNK_SIZE = 10; private final DataSource dataSource; private final SendNotificationItemWriter sendNotificationItemWriter; - public SandNotificationAfterLessonJobConfig(final DataSource dataSource, final SendNotificationItemWriter sendNotificationItemWriter) { + public SendNotificationAfterLessonJobConfig(final DataSource dataSource, final SendNotificationItemWriter sendNotificationItemWriter) { this.dataSource = dataSource; this.sendNotificationItemWriter = sendNotificationItemWriter; } diff --git a/doochul/src/main/java/org/doochul/job/SandNotificationBeforeLessonJobConfig.java b/doochul/src/main/java/org/doochul/job/SendNotificationBeforeLessonJobConfig.java similarity index 97% rename from doochul/src/main/java/org/doochul/job/SandNotificationBeforeLessonJobConfig.java rename to doochul/src/main/java/org/doochul/job/SendNotificationBeforeLessonJobConfig.java index 49bafd0..bb64ecc 100644 --- a/doochul/src/main/java/org/doochul/job/SandNotificationBeforeLessonJobConfig.java +++ b/doochul/src/main/java/org/doochul/job/SendNotificationBeforeLessonJobConfig.java @@ -28,13 +28,13 @@ import static org.doochul.service.LessonStatus.BEFORE_LESSON; @Configuration -public class SandNotificationBeforeLessonJobConfig { +public class SendNotificationBeforeLessonJobConfig { private static final int CHUNK_SIZE = 10; private final DataSource dataSource; private final SendNotificationItemWriter sendNotificationItemWriter; - public SandNotificationBeforeLessonJobConfig(final DataSource dataSource, final SendNotificationItemWriter sendNotificationItemWriter) { + public SendNotificationBeforeLessonJobConfig(final DataSource dataSource, final SendNotificationItemWriter sendNotificationItemWriter) { this.dataSource = dataSource; this.sendNotificationItemWriter = sendNotificationItemWriter; } diff --git a/doochul/src/main/java/org/doochul/service/NotificationService.java b/doochul/src/main/java/org/doochul/service/NotificationService.java index d49bda4..0958bb1 100644 --- a/doochul/src/main/java/org/doochul/service/NotificationService.java +++ b/doochul/src/main/java/org/doochul/service/NotificationService.java @@ -4,29 +4,13 @@ import lombok.extern.slf4j.Slf4j; import org.doochul.application.RedisService; import org.doochul.domain.lesson.Lesson; -import org.doochul.domain.lesson.LessonRepository; -import org.doochul.domain.membership.MemberShip; import org.doochul.domain.user.User; import org.doochul.support.KeyGenerator; -import org.springframework.boot.context.event.ApplicationReadyEvent; -import org.springframework.context.event.EventListener; -import org.springframework.scheduling.TaskScheduler; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; -import java.time.Clock; import java.time.Duration; -import java.time.Instant; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ScheduledFuture; -import static org.doochul.service.LessonStatus.AFTER_LESSON; -import static org.doochul.service.LessonStatus.BEFORE_LESSON; -import static org.doochul.service.LessonStatus.END_LESSON; import static org.doochul.service.LessonStatus.SCHEDULED_LESSON; import static org.doochul.service.LessonStatus.WITHDRAWN_LESSON; @@ -34,38 +18,29 @@ @Service @RequiredArgsConstructor public class NotificationService { - private final TaskScheduler taskScheduler; private final MessageSendManager messageSendManager; - private final Clock clock; - private final LessonRepository lessonRepository; private final KeyGenerator keyGenerator; private final RedisService redisService; - private final Map>> schedule = new HashMap<>(); - - @EventListener(ApplicationReadyEvent.class) - public void initLessonNotification() { - final List lessons = lessonRepository.findByStartedAtBefore(LocalDateTime.now()); - lessons.forEach(lesson -> { - addRemindNotificationSchedule(lesson.getMemberShip().getStudent(), lesson.getMemberShip().getProduct().getTeacher(), lesson); - addDismissalNotificationSchedule(lesson.getMemberShip().getStudent(), lesson.getMemberShip().getProduct().getTeacher(), lesson); - }); - } - public void applyForLesson(final LessonCreateEvent event) { final User student = event.student(); final User teacher = event.teacher(); final Lesson lesson = event.lesson(); - sendNotification(Letter.of(student, teacher, lesson.getStartedAt(), SCHEDULED_LESSON)); - addRemindNotificationSchedule(student,teacher,lesson); - addDismissalNotificationSchedule(student,teacher,lesson); + sendNotification( + Letter.of(student.getDeviceToken(), + student.getName(), + teacher.getName(), + lesson.getStartedAt(), + SCHEDULED_LESSON)); } public void withdrawnForLessons(final LessonWithdrawnEvent event) { - sendNotification(Letter.of(event.student(), event.teacher(), event.lesson().getStartedAt(), WITHDRAWN_LESSON)); - schedule.get(event.lesson().getId()) - .forEach(ScheduledFuture -> ScheduledFuture.cancel(true)); - schedule.remove(event.lesson().getId()); + sendNotification( + Letter.of(event.student().getDeviceToken(), + event.student().getName(), + event.teacher().getName(), + event.lesson().getStartedAt(), + WITHDRAWN_LESSON)); } @Async @@ -76,32 +51,4 @@ public void sendNotification(final Letter letter) { redisService.delete(key); } } - - private void addRemindNotificationSchedule(final User student, final User teacher, final Lesson lesson) { - final LocalDateTime reminderTime = lesson.getStartedAt().minusMinutes(10); - final Instant instant = toInstant(reminderTime); - final ScheduledFuture remindSchedule = taskScheduler.schedule(() -> sendNotification(Letter.of(student, teacher, lesson.getStartedAt(), BEFORE_LESSON)), instant); - final List> lessonSchedules = schedule.computeIfAbsent(lesson.getId(), k -> new ArrayList<>()); - lessonSchedules.add(remindSchedule); - } - - private void addDismissalNotificationSchedule(final User student, final User teacher, final Lesson lesson) { - final Instant instant = toInstant(lesson.getEndedAt()); - final ScheduledFuture dismissalSchedule = taskScheduler.schedule(() -> deductCountAndSendNotification(student, teacher, lesson), instant); - final List> lessonSchedules = schedule.computeIfAbsent(lesson.getId(), k -> new ArrayList<>()); - lessonSchedules.add(dismissalSchedule); - } - - private void deductCountAndSendNotification(final User student, final User teacher, final Lesson lesson) { - final MemberShip memberShip = lesson.getMemberShip(); - memberShip.decreasedCount(); - sendNotification(Letter.of(student, teacher, lesson.getStartedAt(), AFTER_LESSON)); - if (memberShip.isCountZero()) { - sendNotification(Letter.of(student, teacher, lesson.getStartedAt(), END_LESSON)); - } - } - - private Instant toInstant(final LocalDateTime localDateTime) { - return localDateTime.atZone(clock.getZone()).toInstant(); - } } From 1b91c418373cd05ed0ac8548d5d11cb7ba7599b6 Mon Sep 17 00:00:00 2001 From: ingpyo Date: Mon, 11 Mar 2024 15:20:50 +0900 Subject: [PATCH 07/16] =?UTF-8?q?feat:=20TaskExecutor=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SendNotificationAfterLessonJobConfig.java | 23 ++++++++++++++----- ...SendNotificationBeforeLessonJobConfig.java | 14 ++++++++++- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/doochul/src/main/java/org/doochul/job/SendNotificationAfterLessonJobConfig.java b/doochul/src/main/java/org/doochul/job/SendNotificationAfterLessonJobConfig.java index c3457e0..102100f 100644 --- a/doochul/src/main/java/org/doochul/job/SendNotificationAfterLessonJobConfig.java +++ b/doochul/src/main/java/org/doochul/job/SendNotificationAfterLessonJobConfig.java @@ -15,8 +15,9 @@ import org.springframework.batch.item.database.support.SqlPagingQueryProviderFactoryBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.core.task.TaskExecutor; import org.springframework.jdbc.core.ColumnMapRowMapper; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.transaction.PlatformTransactionManager; import javax.sql.DataSource; @@ -49,21 +50,21 @@ public Job sandNotificationAfterLessonJob(JobRepository jobRepository, PlatformT @Bean public Step sendNotificationBeforeClassStep( - JobRepository jobRepository, - PlatformTransactionManager transactionManager + final JobRepository jobRepository, + final PlatformTransactionManager transactionManager ) throws Exception { return new StepBuilder("addNotificationStep", jobRepository) ., Letter>chunk(CHUNK_SIZE, transactionManager) .reader(addNotificationItemReader()) .processor(addNotificationItemProcessor()) .writer(sendNotificationItemWriter) - .taskExecutor(new SimpleAsyncTaskExecutor()) + .taskExecutor(executor()) .build(); } @Bean public JdbcPagingItemReader> addNotificationItemReader() throws Exception { - Map parameterValues = new HashMap<>(); + final Map parameterValues = new HashMap<>(); parameterValues.put("endedAt", LocalDateTime.now()); return new JdbcPagingItemReaderBuilder>() @@ -83,7 +84,7 @@ private PagingQueryProvider createQueryProvider() throws Exception { queryProvider.setFromClause("FROM lesson l JOIN users u ON l.student_id = u.id JOIN users t ON l.teacher_id = t.id"); queryProvider.setWhereClause("WHERE l.ended_at <= :endedAt"); - Map sortKeys = new HashMap<>(1); + final Map sortKeys = new HashMap<>(1); sortKeys.put("l.ended_at", Order.ASCENDING); queryProvider.setSortKeys(sortKeys); @@ -100,4 +101,14 @@ public ItemProcessor, Letter> addNotificationItemProcessor() return Letter.of(studentToken, studentName, teacherName, endedAt, AFTER_LESSON); }; } + + @Bean + public TaskExecutor executor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(4); + executor.setWaitForTasksToCompleteOnShutdown(true); + executor.setAwaitTerminationSeconds(60); + executor.initialize(); + return executor; + } } diff --git a/doochul/src/main/java/org/doochul/job/SendNotificationBeforeLessonJobConfig.java b/doochul/src/main/java/org/doochul/job/SendNotificationBeforeLessonJobConfig.java index bb64ecc..355acb4 100644 --- a/doochul/src/main/java/org/doochul/job/SendNotificationBeforeLessonJobConfig.java +++ b/doochul/src/main/java/org/doochul/job/SendNotificationBeforeLessonJobConfig.java @@ -16,7 +16,9 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.core.task.TaskExecutor; import org.springframework.jdbc.core.ColumnMapRowMapper; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.transaction.PlatformTransactionManager; import javax.sql.DataSource; @@ -57,7 +59,7 @@ public Step sendNotificationBeforeLessonStep( .reader(addNotificationItemReader()) .processor(addNotificationItemProcessor()) .writer(sendNotificationItemWriter) - .taskExecutor(new SimpleAsyncTaskExecutor()) + .taskExecutor(executor()) .build(); } @@ -99,4 +101,14 @@ public ItemProcessor, Letter> addNotificationItemProcessor() return Letter.of(studentToken, studentName, teacherName, startedAt, BEFORE_LESSON); }; } + + @Bean + public TaskExecutor executor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(4); + executor.setWaitForTasksToCompleteOnShutdown(true); + executor.setAwaitTerminationSeconds(60); + executor.initialize(); + return executor; + } } From 81cde926dee485f786407410687e1daa2af9ba96 Mon Sep 17 00:00:00 2001 From: ingpyo Date: Mon, 11 Mar 2024 21:05:59 +0900 Subject: [PATCH 08/16] =?UTF-8?q?feat:=20=ED=8E=98=ED=82=A4=EC=A7=80=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99(service=20->=20application)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{service => application}/MessageSendManager.java | 4 +++- .../NotificationEventListener.java | 4 +++- .../{service => application}/NotificationService.java | 10 ++++++---- .../event}/LessonCreateEvent.java | 2 +- .../event}/LessonWithdrawnEvent.java | 2 +- .../org/doochul/domain/lesson/LessonRepository.java | 1 + .../{service => domain/lesson}/LessonStatus.java | 9 ++++----- .../main/java/org/doochul/infra/FcmMessageSender.java | 4 ++-- .../org/doochul/{service => infra/dto}/Letter.java | 4 +++- .../job/SendNotificationAfterLessonJobConfig.java | 4 ++-- .../job/SendNotificationBeforeLessonJobConfig.java | 5 ++--- .../org/doochul/job/SendNotificationItemWriter.java | 4 ++-- .../java/org/doochul/service/LessonStatusTest.java | 2 ++ .../org/doochul/service/NotificationServiceTest.java | 2 ++ 14 files changed, 34 insertions(+), 23 deletions(-) rename doochul/src/main/java/org/doochul/{service => application}/MessageSendManager.java (52%) rename doochul/src/main/java/org/doochul/{service => application}/NotificationEventListener.java (83%) rename doochul/src/main/java/org/doochul/{service => application}/NotificationService.java (83%) rename doochul/src/main/java/org/doochul/{service => application/event}/LessonCreateEvent.java (82%) rename doochul/src/main/java/org/doochul/{service => application/event}/LessonWithdrawnEvent.java (82%) rename doochul/src/main/java/org/doochul/{service => domain/lesson}/LessonStatus.java (94%) rename doochul/src/main/java/org/doochul/{service => infra/dto}/Letter.java (87%) diff --git a/doochul/src/main/java/org/doochul/service/MessageSendManager.java b/doochul/src/main/java/org/doochul/application/MessageSendManager.java similarity index 52% rename from doochul/src/main/java/org/doochul/service/MessageSendManager.java rename to doochul/src/main/java/org/doochul/application/MessageSendManager.java index 9845d1b..c965f87 100644 --- a/doochul/src/main/java/org/doochul/service/MessageSendManager.java +++ b/doochul/src/main/java/org/doochul/application/MessageSendManager.java @@ -1,4 +1,6 @@ -package org.doochul.service; +package org.doochul.application; + +import org.doochul.infra.dto.Letter; public interface MessageSendManager { void sendTo(final Letter letter); diff --git a/doochul/src/main/java/org/doochul/service/NotificationEventListener.java b/doochul/src/main/java/org/doochul/application/NotificationEventListener.java similarity index 83% rename from doochul/src/main/java/org/doochul/service/NotificationEventListener.java rename to doochul/src/main/java/org/doochul/application/NotificationEventListener.java index d76f5d1..3bc2cf1 100644 --- a/doochul/src/main/java/org/doochul/service/NotificationEventListener.java +++ b/doochul/src/main/java/org/doochul/application/NotificationEventListener.java @@ -1,7 +1,9 @@ -package org.doochul.service; +package org.doochul.application; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.doochul.application.event.LessonCreateEvent; +import org.doochul.application.event.LessonWithdrawnEvent; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; diff --git a/doochul/src/main/java/org/doochul/service/NotificationService.java b/doochul/src/main/java/org/doochul/application/NotificationService.java similarity index 83% rename from doochul/src/main/java/org/doochul/service/NotificationService.java rename to doochul/src/main/java/org/doochul/application/NotificationService.java index 0958bb1..0be0f89 100644 --- a/doochul/src/main/java/org/doochul/service/NotificationService.java +++ b/doochul/src/main/java/org/doochul/application/NotificationService.java @@ -1,18 +1,20 @@ -package org.doochul.service; +package org.doochul.application; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.doochul.application.RedisService; import org.doochul.domain.lesson.Lesson; import org.doochul.domain.user.User; +import org.doochul.application.event.LessonCreateEvent; +import org.doochul.application.event.LessonWithdrawnEvent; +import org.doochul.infra.dto.Letter; import org.doochul.support.KeyGenerator; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.time.Duration; -import static org.doochul.service.LessonStatus.SCHEDULED_LESSON; -import static org.doochul.service.LessonStatus.WITHDRAWN_LESSON; +import static org.doochul.domain.lesson.LessonStatus.SCHEDULED_LESSON; +import static org.doochul.domain.lesson.LessonStatus.WITHDRAWN_LESSON; @Slf4j @Service diff --git a/doochul/src/main/java/org/doochul/service/LessonCreateEvent.java b/doochul/src/main/java/org/doochul/application/event/LessonCreateEvent.java similarity index 82% rename from doochul/src/main/java/org/doochul/service/LessonCreateEvent.java rename to doochul/src/main/java/org/doochul/application/event/LessonCreateEvent.java index 9b5fbb2..9408cd2 100644 --- a/doochul/src/main/java/org/doochul/service/LessonCreateEvent.java +++ b/doochul/src/main/java/org/doochul/application/event/LessonCreateEvent.java @@ -1,4 +1,4 @@ -package org.doochul.service; +package org.doochul.application.event; import org.doochul.domain.lesson.Lesson; import org.doochul.domain.user.User; diff --git a/doochul/src/main/java/org/doochul/service/LessonWithdrawnEvent.java b/doochul/src/main/java/org/doochul/application/event/LessonWithdrawnEvent.java similarity index 82% rename from doochul/src/main/java/org/doochul/service/LessonWithdrawnEvent.java rename to doochul/src/main/java/org/doochul/application/event/LessonWithdrawnEvent.java index d240bdf..98be74b 100644 --- a/doochul/src/main/java/org/doochul/service/LessonWithdrawnEvent.java +++ b/doochul/src/main/java/org/doochul/application/event/LessonWithdrawnEvent.java @@ -1,4 +1,4 @@ -package org.doochul.service; +package org.doochul.application.event; import org.doochul.domain.lesson.Lesson; import org.doochul.domain.user.User; diff --git a/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java b/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java index fb3fe1b..af34bc6 100644 --- a/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java +++ b/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java @@ -11,4 +11,5 @@ default Lesson getById(final Long id) { } List findByStartedAtBefore(final LocalDateTime currentServerTime); + List findOngoingLessons(final LocalDateTime now); } diff --git a/doochul/src/main/java/org/doochul/service/LessonStatus.java b/doochul/src/main/java/org/doochul/domain/lesson/LessonStatus.java similarity index 94% rename from doochul/src/main/java/org/doochul/service/LessonStatus.java rename to doochul/src/main/java/org/doochul/domain/lesson/LessonStatus.java index e47b77f..d5c5c0a 100644 --- a/doochul/src/main/java/org/doochul/service/LessonStatus.java +++ b/doochul/src/main/java/org/doochul/domain/lesson/LessonStatus.java @@ -1,4 +1,6 @@ -package org.doochul.service; +package org.doochul.domain.lesson; + +import lombok.Getter; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -18,6 +20,7 @@ public enum LessonStatus { (name, time, teacher) -> formatToLocalTime(time) + " " + name + "님 " + teacher + " 강사님의 수업을 철회했습니다."), END_LESSON("수업 종료", (name, time, teacher) -> teacher + " 강사님의 수업이 모두 종료되었습니다."); + @Getter private final String title; private final LessonStatusMessage message; @@ -30,10 +33,6 @@ private static String formatToLocalTime(LocalDateTime time) { return time.format(DateTimeFormatter.ofPattern("a HH시 mm분")); } - public String getTitle() { - return title; - } - public String getMessage(String name, LocalDateTime time, String teacher) { return message.getMessage(name, time, teacher); } diff --git a/doochul/src/main/java/org/doochul/infra/FcmMessageSender.java b/doochul/src/main/java/org/doochul/infra/FcmMessageSender.java index d600580..3e2c406 100644 --- a/doochul/src/main/java/org/doochul/infra/FcmMessageSender.java +++ b/doochul/src/main/java/org/doochul/infra/FcmMessageSender.java @@ -9,8 +9,8 @@ import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.doochul.service.Letter; -import org.doochul.service.MessageSendManager; +import org.doochul.infra.dto.Letter; +import org.doochul.application.MessageSendManager; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Component; diff --git a/doochul/src/main/java/org/doochul/service/Letter.java b/doochul/src/main/java/org/doochul/infra/dto/Letter.java similarity index 87% rename from doochul/src/main/java/org/doochul/service/Letter.java rename to doochul/src/main/java/org/doochul/infra/dto/Letter.java index b096ba5..69ad912 100644 --- a/doochul/src/main/java/org/doochul/service/Letter.java +++ b/doochul/src/main/java/org/doochul/infra/dto/Letter.java @@ -1,4 +1,6 @@ -package org.doochul.service; +package org.doochul.infra.dto; + +import org.doochul.domain.lesson.LessonStatus; import java.time.LocalDateTime; diff --git a/doochul/src/main/java/org/doochul/job/SendNotificationAfterLessonJobConfig.java b/doochul/src/main/java/org/doochul/job/SendNotificationAfterLessonJobConfig.java index 102100f..bd69b4a 100644 --- a/doochul/src/main/java/org/doochul/job/SendNotificationAfterLessonJobConfig.java +++ b/doochul/src/main/java/org/doochul/job/SendNotificationAfterLessonJobConfig.java @@ -1,6 +1,6 @@ package org.doochul.job; -import org.doochul.service.Letter; +import org.doochul.infra.dto.Letter; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.job.builder.JobBuilder; @@ -26,7 +26,7 @@ import java.util.Map; import java.util.Optional; -import static org.doochul.service.LessonStatus.AFTER_LESSON; +import static org.doochul.domain.lesson.LessonStatus.AFTER_LESSON; @Configuration public class SendNotificationAfterLessonJobConfig { diff --git a/doochul/src/main/java/org/doochul/job/SendNotificationBeforeLessonJobConfig.java b/doochul/src/main/java/org/doochul/job/SendNotificationBeforeLessonJobConfig.java index 355acb4..0e87e9d 100644 --- a/doochul/src/main/java/org/doochul/job/SendNotificationBeforeLessonJobConfig.java +++ b/doochul/src/main/java/org/doochul/job/SendNotificationBeforeLessonJobConfig.java @@ -1,6 +1,6 @@ package org.doochul.job; -import org.doochul.service.Letter; +import org.doochul.infra.dto.Letter; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.job.builder.JobBuilder; @@ -15,7 +15,6 @@ import org.springframework.batch.item.database.support.SqlPagingQueryProviderFactoryBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.task.SimpleAsyncTaskExecutor; import org.springframework.core.task.TaskExecutor; import org.springframework.jdbc.core.ColumnMapRowMapper; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; @@ -27,7 +26,7 @@ import java.util.Map; import java.util.Optional; -import static org.doochul.service.LessonStatus.BEFORE_LESSON; +import static org.doochul.domain.lesson.LessonStatus.BEFORE_LESSON; @Configuration public class SendNotificationBeforeLessonJobConfig { diff --git a/doochul/src/main/java/org/doochul/job/SendNotificationItemWriter.java b/doochul/src/main/java/org/doochul/job/SendNotificationItemWriter.java index 158f3bc..6ad1e63 100644 --- a/doochul/src/main/java/org/doochul/job/SendNotificationItemWriter.java +++ b/doochul/src/main/java/org/doochul/job/SendNotificationItemWriter.java @@ -1,8 +1,8 @@ package org.doochul.job; import lombok.extern.slf4j.Slf4j; -import org.doochul.service.Letter; -import org.doochul.service.MessageSendManager; +import org.doochul.infra.dto.Letter; +import org.doochul.application.MessageSendManager; import org.springframework.batch.item.Chunk; import org.springframework.batch.item.ItemWriter; import org.springframework.stereotype.Component; diff --git a/doochul/src/test/java/org/doochul/service/LessonStatusTest.java b/doochul/src/test/java/org/doochul/service/LessonStatusTest.java index f8f0b9d..79899b0 100644 --- a/doochul/src/test/java/org/doochul/service/LessonStatusTest.java +++ b/doochul/src/test/java/org/doochul/service/LessonStatusTest.java @@ -4,6 +4,8 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; + +import org.doochul.domain.lesson.LessonStatus; import org.junit.jupiter.api.Test; class LessonStatusTest { diff --git a/doochul/src/test/java/org/doochul/service/NotificationServiceTest.java b/doochul/src/test/java/org/doochul/service/NotificationServiceTest.java index 4af016f..23ffedb 100644 --- a/doochul/src/test/java/org/doochul/service/NotificationServiceTest.java +++ b/doochul/src/test/java/org/doochul/service/NotificationServiceTest.java @@ -1,6 +1,8 @@ package org.doochul.service; +import org.doochul.application.MessageSendManager; import org.doochul.application.RedisService; +import org.doochul.infra.dto.Letter; import org.doochul.support.KeyGenerator; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; From fc7f46cb9b272e19bf5d90a33fcd76b12d2dd925 Mon Sep 17 00:00:00 2001 From: ingpyo Date: Sun, 10 Mar 2024 10:40:55 +0900 Subject: [PATCH 09/16] =?UTF-8?q?feat:=20Batch=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EB=B0=8F=20user=EC=97=94=ED=8B=B0=ED=8B=B0=20=EC=9E=AC?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doochul/build.gradle | 5 ++-- .../java/org/doochul/config/AppConfig.java | 8 ------- .../java/org/doochul/config/AsyncConfig.java | 23 ++++++++++++++++++ .../java/org/doochul/config/BatchConfig.java | 19 +++++++++++++++ .../org/doochul/domain/lesson/Lesson.java | 24 +++++++++++++++++++ .../doochul/domain/membership/MemberShip.java | 8 ++++++- .../org/doochul/domain/product/Product.java | 8 +++++++ .../domain/product/ProductRepository.java | 4 +--- .../java/org/doochul/domain/user/User.java | 15 +++++++++++- .../main/java/org/doochul/service/Letter.java | 11 ++++----- .../src/main/resources/application.properties | 9 +++++-- 11 files changed, 111 insertions(+), 23 deletions(-) create mode 100644 doochul/src/main/java/org/doochul/config/AsyncConfig.java create mode 100644 doochul/src/main/java/org/doochul/config/BatchConfig.java diff --git a/doochul/build.gradle b/doochul/build.gradle index 81f9f50..bd981b9 100644 --- a/doochul/build.gradle +++ b/doochul/build.gradle @@ -26,13 +26,14 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-webflux' implementation 'org.springframework.boot:spring-boot-starter-data-redis' - + implementation 'org.springframework.boot:spring-boot-starter-batch' implementation 'com.google.firebase:firebase-admin:9.2.0' - runtimeOnly 'mysql:mysql-connector-java' + runtimeOnly 'mysql:mysql-connector-java:8.0.28' runtimeOnly 'com.h2database:h2' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.batch:spring-batch-test' testImplementation 'org.springframework.boot:spring-boot-starter-test' } diff --git a/doochul/src/main/java/org/doochul/config/AppConfig.java b/doochul/src/main/java/org/doochul/config/AppConfig.java index 82cab1e..502f671 100644 --- a/doochul/src/main/java/org/doochul/config/AppConfig.java +++ b/doochul/src/main/java/org/doochul/config/AppConfig.java @@ -3,7 +3,6 @@ import java.time.Clock; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; @Configuration public class AppConfig { @@ -12,11 +11,4 @@ public class AppConfig { public Clock clock() { return Clock.systemDefaultZone(); } - - @Bean - public ThreadPoolTaskScheduler taskScheduler() { - ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); - scheduler.setPoolSize(2); - return scheduler; - } } diff --git a/doochul/src/main/java/org/doochul/config/AsyncConfig.java b/doochul/src/main/java/org/doochul/config/AsyncConfig.java new file mode 100644 index 0000000..82db621 --- /dev/null +++ b/doochul/src/main/java/org/doochul/config/AsyncConfig.java @@ -0,0 +1,23 @@ +package org.doochul.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.Executor; + +@EnableAsync +@Configuration +public class AsyncConfig { + + @Bean + public Executor taskExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(8); + executor.setWaitForTasksToCompleteOnShutdown(true); + executor.setAwaitTerminationSeconds(60); + executor.initialize(); + return executor; + } +} \ No newline at end of file diff --git a/doochul/src/main/java/org/doochul/config/BatchConfig.java b/doochul/src/main/java/org/doochul/config/BatchConfig.java new file mode 100644 index 0000000..17189e7 --- /dev/null +++ b/doochul/src/main/java/org/doochul/config/BatchConfig.java @@ -0,0 +1,19 @@ +package org.doochul.config; + +import org.springframework.batch.core.configuration.JobRegistry; +import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; +import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@EnableBatchProcessing +@Configuration +public class BatchConfig { + + @Bean + public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor(JobRegistry jobRegistry) { + JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor = new JobRegistryBeanPostProcessor(); + jobRegistryBeanPostProcessor.setJobRegistry(jobRegistry); + return jobRegistryBeanPostProcessor; + } +} diff --git a/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java b/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java index aca87ee..13542b1 100644 --- a/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java +++ b/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java @@ -12,6 +12,7 @@ import lombok.NoArgsConstructor; import org.doochul.domain.BaseEntity; import org.doochul.domain.membership.MemberShip; +import org.doochul.domain.user.User; @Entity @Getter @@ -26,9 +27,32 @@ public class Lesson extends BaseEntity { @JoinColumn(name = "membership_id") private MemberShip memberShip; + @ManyToOne + @JoinColumn(name = "student_id") + private User student; + + @ManyToOne + @JoinColumn(name = "teacher_id") + private User teacher; + private LocalDateTime startedAt; private LocalDateTime endedAt; private String record; + + public Lesson( + final MemberShip memberShip, + final User student, + final User teacher, + final LocalDateTime startedAt, + final LocalDateTime endedAt + ) { + this.memberShip = memberShip; + this.student = student; + this.teacher = teacher; + this.startedAt = startedAt; + this.endedAt = endedAt; + this.record = null; + } } diff --git a/doochul/src/main/java/org/doochul/domain/membership/MemberShip.java b/doochul/src/main/java/org/doochul/domain/membership/MemberShip.java index 382e41b..84d6d74 100644 --- a/doochul/src/main/java/org/doochul/domain/membership/MemberShip.java +++ b/doochul/src/main/java/org/doochul/domain/membership/MemberShip.java @@ -23,7 +23,7 @@ public class MemberShip extends BaseEntity { private Long id; @ManyToOne - @JoinColumn(name = "user_id") + @JoinColumn(name = "student_id") private User student; @ManyToOne @@ -32,6 +32,12 @@ public class MemberShip extends BaseEntity { private Integer remainingCount; + public MemberShip(final User student, final Product product, final Integer remainingCount) { + this.student = student; + this.product = product; + this.remainingCount = remainingCount; + } + public void decreasedCount() { validateMinRemainingCount(); remainingCount -= 1; diff --git a/doochul/src/main/java/org/doochul/domain/product/Product.java b/doochul/src/main/java/org/doochul/domain/product/Product.java index f9ba1b5..6641b3f 100644 --- a/doochul/src/main/java/org/doochul/domain/product/Product.java +++ b/doochul/src/main/java/org/doochul/domain/product/Product.java @@ -33,4 +33,12 @@ public class Product extends BaseEntity { private User teacher; private Integer count; + + + public Product(final String name, final ProductType type, final User teacher, final Integer count) { + this.name = name; + this.type = type; + this.teacher = teacher; + this.count = count; + } } diff --git a/doochul/src/main/java/org/doochul/domain/product/ProductRepository.java b/doochul/src/main/java/org/doochul/domain/product/ProductRepository.java index d5a3e8e..c62f8c0 100644 --- a/doochul/src/main/java/org/doochul/domain/product/ProductRepository.java +++ b/doochul/src/main/java/org/doochul/domain/product/ProductRepository.java @@ -1,10 +1,8 @@ package org.doochul.domain.product; -import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository -public interface ProductRepository extends JpaRepository { - List findAll(); +public interface ProductRepository extends JpaRepository { } diff --git a/doochul/src/main/java/org/doochul/domain/user/User.java b/doochul/src/main/java/org/doochul/domain/user/User.java index 39391b8..0af8242 100644 --- a/doochul/src/main/java/org/doochul/domain/user/User.java +++ b/doochul/src/main/java/org/doochul/domain/user/User.java @@ -11,7 +11,6 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; -import lombok.RequiredArgsConstructor; import org.doochul.domain.BaseEntity; @Entity @@ -36,4 +35,18 @@ public class User extends BaseEntity { @Enumerated(EnumType.STRING) private Identity identity; + + public User( + final String name, + final String deviceToken, + final String passWord, + final Gender gender, + final Identity identity + ) { + this.name = name; + this.deviceToken = deviceToken; + this.passWord = passWord; + this.gender = gender; + this.identity = identity; + } } diff --git a/doochul/src/main/java/org/doochul/service/Letter.java b/doochul/src/main/java/org/doochul/service/Letter.java index f18da78..b096ba5 100644 --- a/doochul/src/main/java/org/doochul/service/Letter.java +++ b/doochul/src/main/java/org/doochul/service/Letter.java @@ -1,7 +1,5 @@ package org.doochul.service; -import org.doochul.domain.user.User; - import java.time.LocalDateTime; public record Letter( @@ -10,12 +8,13 @@ public record Letter( String body ) { public static Letter of( - final User student, - final User teacher, + final String studentToken, + final String studentName, + final String teacherName, final LocalDateTime startedAt, final LessonStatus lessonStatus ) { - final String message = lessonStatus.getMessage(student.getName(), startedAt, teacher.getName()); - return new Letter(student.getDeviceToken(), lessonStatus.getTitle(), message); + final String message = lessonStatus.getMessage(studentName, startedAt, teacherName); + return new Letter(studentToken, lessonStatus.getTitle(), message); } } diff --git a/doochul/src/main/resources/application.properties b/doochul/src/main/resources/application.properties index 7365132..afb3b70 100644 --- a/doochul/src/main/resources/application.properties +++ b/doochul/src/main/resources/application.properties @@ -1,4 +1,9 @@ -spring.datasource.url=jdbc:h2:mem:testdb;MODE=MySQL; - +#spring.datasource.url=jdbc:h2:mem:testdb;MODE=MySQL; +spring.datasource.url=jdbc:mysql://localhost:3306/my_database?characterEncoding=UTF-8&serverTimezone=Asia/Seoul +spring.datasource.username= root +spring.datasource.password= 123 +spring.jpa.hibernate.ddl-auto=create +spring.jpa.show-sql=true +spring.batch.jdbc.initialize-schema=always fcm.certification.path=kwakdoochul-bbb43-firebase-adminsdk-oyokf-f075393454.json \ No newline at end of file From 3268caf0fb2661149cea444c29516539ffc75b97 Mon Sep 17 00:00:00 2001 From: ingpyo Date: Sun, 10 Mar 2024 10:41:35 +0900 Subject: [PATCH 10/16] =?UTF-8?q?feat:=20Batch=EB=A5=BC=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=B4=20=EC=88=98=EC=97=85=EC=A0=84=20=EB=A6=AC?= =?UTF-8?q?=EB=A7=88=EC=9D=B8=EB=93=9C=20=EC=95=8C=EB=9E=8C=20=EC=8A=A4?= =?UTF-8?q?=EC=BC=80=EC=A4=84=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SandNotificationBeforeClassJobConfig.java | 98 +++++++++++++++++++ .../job/SendNotificationItemWriter.java | 25 +++++ 2 files changed, 123 insertions(+) create mode 100644 doochul/src/main/java/org/doochul/job/SandNotificationBeforeClassJobConfig.java create mode 100644 doochul/src/main/java/org/doochul/job/SendNotificationItemWriter.java diff --git a/doochul/src/main/java/org/doochul/job/SandNotificationBeforeClassJobConfig.java b/doochul/src/main/java/org/doochul/job/SandNotificationBeforeClassJobConfig.java new file mode 100644 index 0000000..2baef24 --- /dev/null +++ b/doochul/src/main/java/org/doochul/job/SandNotificationBeforeClassJobConfig.java @@ -0,0 +1,98 @@ +package org.doochul.job; + +import org.doochul.service.Letter; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.job.builder.JobBuilder; +import org.springframework.batch.core.launch.support.RunIdIncrementer; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.step.builder.StepBuilder; +import org.springframework.batch.item.ItemProcessor; +import org.springframework.batch.item.database.JdbcPagingItemReader; +import org.springframework.batch.item.database.PagingQueryProvider; +import org.springframework.batch.item.database.builder.JdbcPagingItemReaderBuilder; +import org.springframework.batch.item.database.support.SqlPagingQueryProviderFactoryBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.jdbc.core.ColumnMapRowMapper; +import org.springframework.transaction.PlatformTransactionManager; + +import javax.sql.DataSource; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +import static org.doochul.service.LessonStatus.BEFORE_LESSON; + +@Configuration +public class SandNotificationBeforeClassJobConfig { + private static final int CHUNK_SIZE = 10; + + private final DataSource dataSource; + private final SendNotificationItemWriter sendNotificationItemWriter; + + public SandNotificationBeforeClassJobConfig(final DataSource dataSource, final SendNotificationItemWriter sendNotificationItemWriter) { + this.dataSource = dataSource; + this.sendNotificationItemWriter = sendNotificationItemWriter; + } + + @Bean + public Job sendNotificationBeforeClassJob(JobRepository jobRepository, PlatformTransactionManager transactionManager) throws Exception { + return new JobBuilder("sendNotificationBeforeClassJob", jobRepository) + .incrementer(new RunIdIncrementer()) + .start(sendNotificationBeforeClassStep(jobRepository, transactionManager)) + .build(); + } + + @Bean + public Step sendNotificationBeforeClassStep( + JobRepository jobRepository, + PlatformTransactionManager transactionManager + ) throws Exception { + return new StepBuilder("addNotificationStep", jobRepository) + ., Letter>chunk(CHUNK_SIZE, transactionManager) + .reader(addNotificationItemReader()) + .processor(addNotificationItemProcessor()) + .writer(sendNotificationItemWriter) + .taskExecutor(new SimpleAsyncTaskExecutor()) + .build(); + } + + @Bean + public JdbcPagingItemReader> addNotificationItemReader() throws Exception { + Map parameterValues = new HashMap<>(); + parameterValues.put("startedAt", LocalDateTime.now().plusMinutes(10)); + + return new JdbcPagingItemReaderBuilder>() + .name("addNotificationItemReader") + .dataSource(dataSource) + .pageSize(CHUNK_SIZE) + .queryProvider(createQueryProvider()) + .parameterValues(parameterValues) + .rowMapper(new ColumnMapRowMapper()) + .build(); + } + + private PagingQueryProvider createQueryProvider() throws Exception { + SqlPagingQueryProviderFactoryBean queryProvider = new SqlPagingQueryProviderFactoryBean(); + queryProvider.setDataSource(dataSource); + queryProvider.setSelectClause("u.device_token AS student_token, u.name AS student_name, t.name AS teacher_name, l.started_at"); + queryProvider.setFromClause("FROM lesson l JOIN users u ON l.student_id = u.id JOIN users t ON l.teacher_id = t.id"); + queryProvider.setWhereClause("WHERE l.started_at <= :startedAt"); + + return queryProvider.getObject(); + } + + @Bean + public ItemProcessor, Letter> addNotificationItemProcessor() { + return item -> { + String studentToken = (String) item.get("student_token"); + String studentName = (String) item.get("student_name"); + String teacherName = (String) item.get("teacher_name"); + LocalDateTime startedAt = (LocalDateTime) item.get("started_at"); + + return Letter.of(studentToken, studentName, teacherName, startedAt, BEFORE_LESSON); + }; + } +} diff --git a/doochul/src/main/java/org/doochul/job/SendNotificationItemWriter.java b/doochul/src/main/java/org/doochul/job/SendNotificationItemWriter.java new file mode 100644 index 0000000..158f3bc --- /dev/null +++ b/doochul/src/main/java/org/doochul/job/SendNotificationItemWriter.java @@ -0,0 +1,25 @@ +package org.doochul.job; + +import lombok.extern.slf4j.Slf4j; +import org.doochul.service.Letter; +import org.doochul.service.MessageSendManager; +import org.springframework.batch.item.Chunk; +import org.springframework.batch.item.ItemWriter; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class SendNotificationItemWriter implements ItemWriter { + private final MessageSendManager messageSendManager; + + public SendNotificationItemWriter(MessageSendManager messageSendManager) { + this.messageSendManager = messageSendManager; + } + + @Override + public void write(final Chunk letters) { + for (final Letter letter : letters) { + messageSendManager.sendTo(letter); + } + } +} From e82ad1627624bd09a04c535bb7d4aecc75c24285 Mon Sep 17 00:00:00 2001 From: ingpyo Date: Sun, 10 Mar 2024 19:41:16 +0900 Subject: [PATCH 11/16] =?UTF-8?q?feat:=20Batch=EB=A5=BC=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=B4=20=EC=88=98=EC=97=85=EC=A0=84=20=EB=A6=AC?= =?UTF-8?q?=EB=A7=88=EC=9D=B8=EB=93=9C=20=EC=95=8C=EB=9E=8C=20=EC=8A=A4?= =?UTF-8?q?=EC=BC=80=EC=A4=84=20=EC=9E=91=EC=84=B1(JPA=20->=20=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=EB=A1=9C=20=EB=B3=80=EA=B2=BD)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...andNotificationBeforeLessonJobConfig.java} | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) rename doochul/src/main/java/org/doochul/job/{SandNotificationBeforeClassJobConfig.java => SandNotificationBeforeLessonJobConfig.java} (78%) diff --git a/doochul/src/main/java/org/doochul/job/SandNotificationBeforeClassJobConfig.java b/doochul/src/main/java/org/doochul/job/SandNotificationBeforeLessonJobConfig.java similarity index 78% rename from doochul/src/main/java/org/doochul/job/SandNotificationBeforeClassJobConfig.java rename to doochul/src/main/java/org/doochul/job/SandNotificationBeforeLessonJobConfig.java index 2baef24..49bafd0 100644 --- a/doochul/src/main/java/org/doochul/job/SandNotificationBeforeClassJobConfig.java +++ b/doochul/src/main/java/org/doochul/job/SandNotificationBeforeLessonJobConfig.java @@ -9,6 +9,7 @@ import org.springframework.batch.core.step.builder.StepBuilder; import org.springframework.batch.item.ItemProcessor; import org.springframework.batch.item.database.JdbcPagingItemReader; +import org.springframework.batch.item.database.Order; import org.springframework.batch.item.database.PagingQueryProvider; import org.springframework.batch.item.database.builder.JdbcPagingItemReaderBuilder; import org.springframework.batch.item.database.support.SqlPagingQueryProviderFactoryBean; @@ -22,31 +23,32 @@ import java.time.LocalDateTime; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import static org.doochul.service.LessonStatus.BEFORE_LESSON; @Configuration -public class SandNotificationBeforeClassJobConfig { +public class SandNotificationBeforeLessonJobConfig { private static final int CHUNK_SIZE = 10; private final DataSource dataSource; private final SendNotificationItemWriter sendNotificationItemWriter; - public SandNotificationBeforeClassJobConfig(final DataSource dataSource, final SendNotificationItemWriter sendNotificationItemWriter) { + public SandNotificationBeforeLessonJobConfig(final DataSource dataSource, final SendNotificationItemWriter sendNotificationItemWriter) { this.dataSource = dataSource; this.sendNotificationItemWriter = sendNotificationItemWriter; } @Bean - public Job sendNotificationBeforeClassJob(JobRepository jobRepository, PlatformTransactionManager transactionManager) throws Exception { - return new JobBuilder("sendNotificationBeforeClassJob", jobRepository) + public Job sandNotificationBeforeLessonJob(JobRepository jobRepository, PlatformTransactionManager transactionManager) throws Exception { + return new JobBuilder("sandNotificationBeforeLessonJob", jobRepository) .incrementer(new RunIdIncrementer()) - .start(sendNotificationBeforeClassStep(jobRepository, transactionManager)) + .start(sendNotificationBeforeLessonStep(jobRepository, transactionManager)) .build(); } @Bean - public Step sendNotificationBeforeClassStep( + public Step sendNotificationBeforeLessonStep( JobRepository jobRepository, PlatformTransactionManager transactionManager ) throws Exception { @@ -77,11 +79,14 @@ public JdbcPagingItemReader> addNotificationItemReader() thr private PagingQueryProvider createQueryProvider() throws Exception { SqlPagingQueryProviderFactoryBean queryProvider = new SqlPagingQueryProviderFactoryBean(); queryProvider.setDataSource(dataSource); - queryProvider.setSelectClause("u.device_token AS student_token, u.name AS student_name, t.name AS teacher_name, l.started_at"); + queryProvider.setSelectClause("SELECT u.device_token AS student_token, u.name AS student_name, t.name AS teacher_name, l.started_at"); queryProvider.setFromClause("FROM lesson l JOIN users u ON l.student_id = u.id JOIN users t ON l.teacher_id = t.id"); queryProvider.setWhereClause("WHERE l.started_at <= :startedAt"); + Map sortKeys = new HashMap<>(1); + sortKeys.put("l.started_at", Order.ASCENDING); - return queryProvider.getObject(); + queryProvider.setSortKeys(sortKeys); + return Optional.ofNullable(queryProvider.getObject()).orElseThrow(IllegalArgumentException::new); } @Bean @@ -91,7 +96,6 @@ public ItemProcessor, Letter> addNotificationItemProcessor() String studentName = (String) item.get("student_name"); String teacherName = (String) item.get("teacher_name"); LocalDateTime startedAt = (LocalDateTime) item.get("started_at"); - return Letter.of(studentToken, studentName, teacherName, startedAt, BEFORE_LESSON); }; } From c28296fe1832f397abe318356ab3961ca2ec8712 Mon Sep 17 00:00:00 2001 From: ingpyo Date: Sun, 10 Mar 2024 20:27:23 +0900 Subject: [PATCH 12/16] =?UTF-8?q?feat:=20Batch=EB=A5=BC=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=B4=20=EC=88=98=EC=97=85=ED=9B=84=20=EC=95=8C?= =?UTF-8?q?=EB=9E=8C=20=EB=B0=8F=20=EC=9D=B4=EC=9A=A9=EA=B6=8C=20=EA=B0=9C?= =?UTF-8?q?=EC=88=98=20=EC=B0=A8=EA=B0=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SandNotificationAfterLessonJobConfig.java | 103 ++++++++++++++++++ .../job/UpdateRemainingCountJobConfig.java | 52 +++++++++ 2 files changed, 155 insertions(+) create mode 100644 doochul/src/main/java/org/doochul/job/SandNotificationAfterLessonJobConfig.java create mode 100644 doochul/src/main/java/org/doochul/job/UpdateRemainingCountJobConfig.java diff --git a/doochul/src/main/java/org/doochul/job/SandNotificationAfterLessonJobConfig.java b/doochul/src/main/java/org/doochul/job/SandNotificationAfterLessonJobConfig.java new file mode 100644 index 0000000..a089b15 --- /dev/null +++ b/doochul/src/main/java/org/doochul/job/SandNotificationAfterLessonJobConfig.java @@ -0,0 +1,103 @@ +package org.doochul.job; + +import org.doochul.service.Letter; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.job.builder.JobBuilder; +import org.springframework.batch.core.launch.support.RunIdIncrementer; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.step.builder.StepBuilder; +import org.springframework.batch.item.ItemProcessor; +import org.springframework.batch.item.database.JdbcPagingItemReader; +import org.springframework.batch.item.database.Order; +import org.springframework.batch.item.database.PagingQueryProvider; +import org.springframework.batch.item.database.builder.JdbcPagingItemReaderBuilder; +import org.springframework.batch.item.database.support.SqlPagingQueryProviderFactoryBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.jdbc.core.ColumnMapRowMapper; +import org.springframework.transaction.PlatformTransactionManager; + +import javax.sql.DataSource; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import static org.doochul.service.LessonStatus.AFTER_LESSON; + +@Configuration +public class SandNotificationAfterLessonJobConfig { + private static final int CHUNK_SIZE = 10; + + private final DataSource dataSource; + private final SendNotificationItemWriter sendNotificationItemWriter; + + public SandNotificationAfterLessonJobConfig(final DataSource dataSource, final SendNotificationItemWriter sendNotificationItemWriter) { + this.dataSource = dataSource; + this.sendNotificationItemWriter = sendNotificationItemWriter; + } + + @Bean + public Job sandNotificationAfterLessonJob(JobRepository jobRepository, PlatformTransactionManager transactionManager) throws Exception { + return new JobBuilder("sandNotificationAfterLesson", jobRepository) + .incrementer(new RunIdIncrementer()) + .start(sendNotificationBeforeClassStep(jobRepository, transactionManager)) + .build(); + } + + @Bean + public Step sendNotificationBeforeClassStep( + JobRepository jobRepository, + PlatformTransactionManager transactionManager + ) throws Exception { + return new StepBuilder("addNotificationStep", jobRepository) + ., Letter>chunk(CHUNK_SIZE, transactionManager) + .reader(addNotificationItemReader()) + .processor(addNotificationItemProcessor()) + .writer(sendNotificationItemWriter) + .taskExecutor(new SimpleAsyncTaskExecutor()) + .build(); + } + + @Bean + public JdbcPagingItemReader> addNotificationItemReader() throws Exception { + Map parameterValues = new HashMap<>(); + parameterValues.put("endedAt", LocalDateTime.now()); + + return new JdbcPagingItemReaderBuilder>() + .name("addNotificationItemReader") + .dataSource(dataSource) + .pageSize(CHUNK_SIZE) + .queryProvider(createQueryProvider()) + .parameterValues(parameterValues) + .rowMapper(new ColumnMapRowMapper()) + .build(); + } + + private PagingQueryProvider createQueryProvider() throws Exception { + SqlPagingQueryProviderFactoryBean queryProvider = new SqlPagingQueryProviderFactoryBean(); + queryProvider.setDataSource(dataSource); + queryProvider.setSelectClause("SELECT u.device_token AS student_token, u.name AS student_name, t.name AS teacher_name, l.ended_at"); + queryProvider.setFromClause("FROM lesson l JOIN users u ON l.student_id = u.id JOIN users t ON l.teacher_id = t.id"); + queryProvider.setWhereClause("WHERE l.ended_at <= :endedAt"); + + Map sortKeys = new HashMap<>(1); + sortKeys.put("l.ended_at", Order.ASCENDING); + + queryProvider.setSortKeys(sortKeys); + return Optional.ofNullable(queryProvider.getObject()).orElseThrow(IllegalArgumentException::new); + } + + @Bean + public ItemProcessor, Letter> addNotificationItemProcessor() { + return item -> { + String studentToken = (String) item.get("student_token"); + String studentName = (String) item.get("student_name"); + String teacherName = (String) item.get("teacher_name"); + LocalDateTime endedAt = (LocalDateTime) item.get("ended_at"); + return Letter.of(studentToken, studentName, teacherName, endedAt, AFTER_LESSON); + }; + } +} diff --git a/doochul/src/main/java/org/doochul/job/UpdateRemainingCountJobConfig.java b/doochul/src/main/java/org/doochul/job/UpdateRemainingCountJobConfig.java new file mode 100644 index 0000000..e9340f7 --- /dev/null +++ b/doochul/src/main/java/org/doochul/job/UpdateRemainingCountJobConfig.java @@ -0,0 +1,52 @@ +package org.doochul.job; + +import org.springframework.batch.core.Job; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.StepContribution; +import org.springframework.batch.core.job.builder.JobBuilder; +import org.springframework.batch.core.launch.support.RunIdIncrementer; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.scope.context.ChunkContext; +import org.springframework.batch.core.step.builder.StepBuilder; +import org.springframework.batch.core.step.tasklet.Tasklet; +import org.springframework.batch.repeat.RepeatStatus; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.transaction.PlatformTransactionManager; + +import java.time.LocalDateTime; +import java.util.Collections; + +@Configuration +public class UpdateRemainingCountJobConfig { + @Bean + public Step updateRemainingCountStep(JobRepository jobRepository, PlatformTransactionManager transactionManager, JdbcTemplate jdbcTemplate) { + return new StepBuilder("updateRemainingCountStep", jobRepository) + .tasklet(new UpdateRemainingCountTasklet(jdbcTemplate), transactionManager) + .build(); + } + + @Bean + public Job updateRemainingCountJob(JobRepository jobRepository, PlatformTransactionManager transactionManager, JdbcTemplate jdbcTemplate) { + return new JobBuilder("updateRemainingCountJob", jobRepository) + .incrementer(new RunIdIncrementer()) + .start(updateRemainingCountStep(jobRepository, transactionManager, jdbcTemplate)) + .build(); + } + + private static class UpdateRemainingCountTasklet implements Tasklet { + private final JdbcTemplate jdbcTemplate; + + public UpdateRemainingCountTasklet(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + @Override + public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) { + jdbcTemplate.update("UPDATE lesson JOIN member_ship m ON l.membership_id = m.id SET m.remaining_count = m.remaining_count - 1 WHERE l.ended_at <= :endedAt", + Collections.singletonMap("endedAt", LocalDateTime.now())); + return RepeatStatus.FINISHED; + } + } +} From df923577c27e338881a79974b582c375328e1aa2 Mon Sep 17 00:00:00 2001 From: ingpyo Date: Sun, 10 Mar 2024 20:36:52 +0900 Subject: [PATCH 13/16] =?UTF-8?q?feat:=20job=EC=9D=84=20=EC=8B=A4=ED=96=89?= =?UTF-8?q?=EC=8B=9C=ED=82=A4=EB=8A=94=20=EC=8A=A4=EC=BC=80=EC=A4=84?= =?UTF-8?q?=EB=9F=AC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/doochul/job/BatchScheduler.java | 42 +++++++++++++++++++ .../job/UpdateRemainingCountJobConfig.java | 14 +++---- 2 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 doochul/src/main/java/org/doochul/job/BatchScheduler.java diff --git a/doochul/src/main/java/org/doochul/job/BatchScheduler.java b/doochul/src/main/java/org/doochul/job/BatchScheduler.java new file mode 100644 index 0000000..695dc31 --- /dev/null +++ b/doochul/src/main/java/org/doochul/job/BatchScheduler.java @@ -0,0 +1,42 @@ +package org.doochul.job; + +import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.JobParametersBuilder; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Component +public class BatchScheduler { + + private final JobLauncher jobLauncher; + private final Job sandNotificationAfterLessonJob; + private final Job sandNotificationBeforeLessonJob; + private final Job updateRemainingCountJob; + + public BatchScheduler(JobLauncher jobLauncher, + @Qualifier("sandNotificationAfterLessonJob") Job sandNotificationAfterLessonJob, + @Qualifier("sandNotificationBeforeLessonJob") Job sandNotificationBeforeLessonJob, + @Qualifier("updateRemainingCountJob") Job updateRemainingCountJob) { + this.jobLauncher = jobLauncher; + this.sandNotificationAfterLessonJob = sandNotificationAfterLessonJob; + this.sandNotificationBeforeLessonJob = sandNotificationBeforeLessonJob; + this.updateRemainingCountJob = updateRemainingCountJob; + } + + @Scheduled(cron = "0 0/1 * * * *") + public void runJobs() throws Exception { + runJob(sandNotificationAfterLessonJob); + runJob(sandNotificationBeforeLessonJob); + runJob(updateRemainingCountJob); + } + + private void runJob(Job job) throws Exception { + JobParameters parameters = new JobParametersBuilder() + .addString("jobName: ", job.getName() + System.currentTimeMillis()) + .toJobParameters(); + jobLauncher.run(job, parameters); + } +} \ No newline at end of file diff --git a/doochul/src/main/java/org/doochul/job/UpdateRemainingCountJobConfig.java b/doochul/src/main/java/org/doochul/job/UpdateRemainingCountJobConfig.java index e9340f7..f755e79 100644 --- a/doochul/src/main/java/org/doochul/job/UpdateRemainingCountJobConfig.java +++ b/doochul/src/main/java/org/doochul/job/UpdateRemainingCountJobConfig.java @@ -20,13 +20,6 @@ @Configuration public class UpdateRemainingCountJobConfig { - @Bean - public Step updateRemainingCountStep(JobRepository jobRepository, PlatformTransactionManager transactionManager, JdbcTemplate jdbcTemplate) { - return new StepBuilder("updateRemainingCountStep", jobRepository) - .tasklet(new UpdateRemainingCountTasklet(jdbcTemplate), transactionManager) - .build(); - } - @Bean public Job updateRemainingCountJob(JobRepository jobRepository, PlatformTransactionManager transactionManager, JdbcTemplate jdbcTemplate) { return new JobBuilder("updateRemainingCountJob", jobRepository) @@ -35,7 +28,14 @@ public Job updateRemainingCountJob(JobRepository jobRepository, PlatformTransact .build(); } + @Bean + public Step updateRemainingCountStep(JobRepository jobRepository, PlatformTransactionManager transactionManager, JdbcTemplate jdbcTemplate) { + return new StepBuilder("updateRemainingCountStep", jobRepository) + .tasklet(new UpdateRemainingCountTasklet(jdbcTemplate), transactionManager) + .build(); + } private static class UpdateRemainingCountTasklet implements Tasklet { + private final JdbcTemplate jdbcTemplate; public UpdateRemainingCountTasklet(JdbcTemplate jdbcTemplate) { From d4f8655c90c78f9163563bf723b042a2cc9d0f69 Mon Sep 17 00:00:00 2001 From: ingpyo Date: Mon, 11 Mar 2024 15:10:32 +0900 Subject: [PATCH 14/16] =?UTF-8?q?feat:=20batch=EB=A1=9C=20=EC=8A=A4?= =?UTF-8?q?=EC=BC=80=EC=A4=84=20=EB=A1=9C=EC=A7=81=20=EC=9D=B4=EB=8F=99=20?= =?UTF-8?q?=EB=B0=8F=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EB=84=A4=EC=9D=B4?= =?UTF-8?q?=EB=B0=8D=20=EC=98=A4=ED=83=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/doochul/application/RedisService.java | 1 - .../java/org/doochul/config/AsyncConfig.java | 2 +- .../org/doochul/domain/product/Product.java | 1 - ...SendNotificationAfterLessonJobConfig.java} | 4 +- ...endNotificationBeforeLessonJobConfig.java} | 4 +- .../doochul/service/NotificationService.java | 77 +++---------------- 6 files changed, 17 insertions(+), 72 deletions(-) rename doochul/src/main/java/org/doochul/job/{SandNotificationAfterLessonJobConfig.java => SendNotificationAfterLessonJobConfig.java} (97%) rename doochul/src/main/java/org/doochul/job/{SandNotificationBeforeLessonJobConfig.java => SendNotificationBeforeLessonJobConfig.java} (97%) diff --git a/doochul/src/main/java/org/doochul/application/RedisService.java b/doochul/src/main/java/org/doochul/application/RedisService.java index 5bd1be3..5c37dc1 100644 --- a/doochul/src/main/java/org/doochul/application/RedisService.java +++ b/doochul/src/main/java/org/doochul/application/RedisService.java @@ -18,7 +18,6 @@ public void delete(final String key) { redisTemplate.delete(key); } - public boolean setNX(final String key, final String value, final Duration duration) { return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, value, duration)); } diff --git a/doochul/src/main/java/org/doochul/config/AsyncConfig.java b/doochul/src/main/java/org/doochul/config/AsyncConfig.java index 82db621..fed0d58 100644 --- a/doochul/src/main/java/org/doochul/config/AsyncConfig.java +++ b/doochul/src/main/java/org/doochul/config/AsyncConfig.java @@ -14,7 +14,7 @@ public class AsyncConfig { @Bean public Executor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); - executor.setCorePoolSize(8); + executor.setCorePoolSize(4); executor.setWaitForTasksToCompleteOnShutdown(true); executor.setAwaitTerminationSeconds(60); executor.initialize(); diff --git a/doochul/src/main/java/org/doochul/domain/product/Product.java b/doochul/src/main/java/org/doochul/domain/product/Product.java index 6641b3f..e43cd98 100644 --- a/doochul/src/main/java/org/doochul/domain/product/Product.java +++ b/doochul/src/main/java/org/doochul/domain/product/Product.java @@ -34,7 +34,6 @@ public class Product extends BaseEntity { private Integer count; - public Product(final String name, final ProductType type, final User teacher, final Integer count) { this.name = name; this.type = type; diff --git a/doochul/src/main/java/org/doochul/job/SandNotificationAfterLessonJobConfig.java b/doochul/src/main/java/org/doochul/job/SendNotificationAfterLessonJobConfig.java similarity index 97% rename from doochul/src/main/java/org/doochul/job/SandNotificationAfterLessonJobConfig.java rename to doochul/src/main/java/org/doochul/job/SendNotificationAfterLessonJobConfig.java index a089b15..c3457e0 100644 --- a/doochul/src/main/java/org/doochul/job/SandNotificationAfterLessonJobConfig.java +++ b/doochul/src/main/java/org/doochul/job/SendNotificationAfterLessonJobConfig.java @@ -28,13 +28,13 @@ import static org.doochul.service.LessonStatus.AFTER_LESSON; @Configuration -public class SandNotificationAfterLessonJobConfig { +public class SendNotificationAfterLessonJobConfig { private static final int CHUNK_SIZE = 10; private final DataSource dataSource; private final SendNotificationItemWriter sendNotificationItemWriter; - public SandNotificationAfterLessonJobConfig(final DataSource dataSource, final SendNotificationItemWriter sendNotificationItemWriter) { + public SendNotificationAfterLessonJobConfig(final DataSource dataSource, final SendNotificationItemWriter sendNotificationItemWriter) { this.dataSource = dataSource; this.sendNotificationItemWriter = sendNotificationItemWriter; } diff --git a/doochul/src/main/java/org/doochul/job/SandNotificationBeforeLessonJobConfig.java b/doochul/src/main/java/org/doochul/job/SendNotificationBeforeLessonJobConfig.java similarity index 97% rename from doochul/src/main/java/org/doochul/job/SandNotificationBeforeLessonJobConfig.java rename to doochul/src/main/java/org/doochul/job/SendNotificationBeforeLessonJobConfig.java index 49bafd0..bb64ecc 100644 --- a/doochul/src/main/java/org/doochul/job/SandNotificationBeforeLessonJobConfig.java +++ b/doochul/src/main/java/org/doochul/job/SendNotificationBeforeLessonJobConfig.java @@ -28,13 +28,13 @@ import static org.doochul.service.LessonStatus.BEFORE_LESSON; @Configuration -public class SandNotificationBeforeLessonJobConfig { +public class SendNotificationBeforeLessonJobConfig { private static final int CHUNK_SIZE = 10; private final DataSource dataSource; private final SendNotificationItemWriter sendNotificationItemWriter; - public SandNotificationBeforeLessonJobConfig(final DataSource dataSource, final SendNotificationItemWriter sendNotificationItemWriter) { + public SendNotificationBeforeLessonJobConfig(final DataSource dataSource, final SendNotificationItemWriter sendNotificationItemWriter) { this.dataSource = dataSource; this.sendNotificationItemWriter = sendNotificationItemWriter; } diff --git a/doochul/src/main/java/org/doochul/service/NotificationService.java b/doochul/src/main/java/org/doochul/service/NotificationService.java index d49bda4..0958bb1 100644 --- a/doochul/src/main/java/org/doochul/service/NotificationService.java +++ b/doochul/src/main/java/org/doochul/service/NotificationService.java @@ -4,29 +4,13 @@ import lombok.extern.slf4j.Slf4j; import org.doochul.application.RedisService; import org.doochul.domain.lesson.Lesson; -import org.doochul.domain.lesson.LessonRepository; -import org.doochul.domain.membership.MemberShip; import org.doochul.domain.user.User; import org.doochul.support.KeyGenerator; -import org.springframework.boot.context.event.ApplicationReadyEvent; -import org.springframework.context.event.EventListener; -import org.springframework.scheduling.TaskScheduler; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; -import java.time.Clock; import java.time.Duration; -import java.time.Instant; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ScheduledFuture; -import static org.doochul.service.LessonStatus.AFTER_LESSON; -import static org.doochul.service.LessonStatus.BEFORE_LESSON; -import static org.doochul.service.LessonStatus.END_LESSON; import static org.doochul.service.LessonStatus.SCHEDULED_LESSON; import static org.doochul.service.LessonStatus.WITHDRAWN_LESSON; @@ -34,38 +18,29 @@ @Service @RequiredArgsConstructor public class NotificationService { - private final TaskScheduler taskScheduler; private final MessageSendManager messageSendManager; - private final Clock clock; - private final LessonRepository lessonRepository; private final KeyGenerator keyGenerator; private final RedisService redisService; - private final Map>> schedule = new HashMap<>(); - - @EventListener(ApplicationReadyEvent.class) - public void initLessonNotification() { - final List lessons = lessonRepository.findByStartedAtBefore(LocalDateTime.now()); - lessons.forEach(lesson -> { - addRemindNotificationSchedule(lesson.getMemberShip().getStudent(), lesson.getMemberShip().getProduct().getTeacher(), lesson); - addDismissalNotificationSchedule(lesson.getMemberShip().getStudent(), lesson.getMemberShip().getProduct().getTeacher(), lesson); - }); - } - public void applyForLesson(final LessonCreateEvent event) { final User student = event.student(); final User teacher = event.teacher(); final Lesson lesson = event.lesson(); - sendNotification(Letter.of(student, teacher, lesson.getStartedAt(), SCHEDULED_LESSON)); - addRemindNotificationSchedule(student,teacher,lesson); - addDismissalNotificationSchedule(student,teacher,lesson); + sendNotification( + Letter.of(student.getDeviceToken(), + student.getName(), + teacher.getName(), + lesson.getStartedAt(), + SCHEDULED_LESSON)); } public void withdrawnForLessons(final LessonWithdrawnEvent event) { - sendNotification(Letter.of(event.student(), event.teacher(), event.lesson().getStartedAt(), WITHDRAWN_LESSON)); - schedule.get(event.lesson().getId()) - .forEach(ScheduledFuture -> ScheduledFuture.cancel(true)); - schedule.remove(event.lesson().getId()); + sendNotification( + Letter.of(event.student().getDeviceToken(), + event.student().getName(), + event.teacher().getName(), + event.lesson().getStartedAt(), + WITHDRAWN_LESSON)); } @Async @@ -76,32 +51,4 @@ public void sendNotification(final Letter letter) { redisService.delete(key); } } - - private void addRemindNotificationSchedule(final User student, final User teacher, final Lesson lesson) { - final LocalDateTime reminderTime = lesson.getStartedAt().minusMinutes(10); - final Instant instant = toInstant(reminderTime); - final ScheduledFuture remindSchedule = taskScheduler.schedule(() -> sendNotification(Letter.of(student, teacher, lesson.getStartedAt(), BEFORE_LESSON)), instant); - final List> lessonSchedules = schedule.computeIfAbsent(lesson.getId(), k -> new ArrayList<>()); - lessonSchedules.add(remindSchedule); - } - - private void addDismissalNotificationSchedule(final User student, final User teacher, final Lesson lesson) { - final Instant instant = toInstant(lesson.getEndedAt()); - final ScheduledFuture dismissalSchedule = taskScheduler.schedule(() -> deductCountAndSendNotification(student, teacher, lesson), instant); - final List> lessonSchedules = schedule.computeIfAbsent(lesson.getId(), k -> new ArrayList<>()); - lessonSchedules.add(dismissalSchedule); - } - - private void deductCountAndSendNotification(final User student, final User teacher, final Lesson lesson) { - final MemberShip memberShip = lesson.getMemberShip(); - memberShip.decreasedCount(); - sendNotification(Letter.of(student, teacher, lesson.getStartedAt(), AFTER_LESSON)); - if (memberShip.isCountZero()) { - sendNotification(Letter.of(student, teacher, lesson.getStartedAt(), END_LESSON)); - } - } - - private Instant toInstant(final LocalDateTime localDateTime) { - return localDateTime.atZone(clock.getZone()).toInstant(); - } } From 8a1cdce88bf145955b60be28fa51e1769491e55e Mon Sep 17 00:00:00 2001 From: ingpyo Date: Mon, 11 Mar 2024 15:20:50 +0900 Subject: [PATCH 15/16] =?UTF-8?q?feat:=20TaskExecutor=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SendNotificationAfterLessonJobConfig.java | 23 ++++++++++++++----- ...SendNotificationBeforeLessonJobConfig.java | 14 ++++++++++- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/doochul/src/main/java/org/doochul/job/SendNotificationAfterLessonJobConfig.java b/doochul/src/main/java/org/doochul/job/SendNotificationAfterLessonJobConfig.java index c3457e0..102100f 100644 --- a/doochul/src/main/java/org/doochul/job/SendNotificationAfterLessonJobConfig.java +++ b/doochul/src/main/java/org/doochul/job/SendNotificationAfterLessonJobConfig.java @@ -15,8 +15,9 @@ import org.springframework.batch.item.database.support.SqlPagingQueryProviderFactoryBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.core.task.TaskExecutor; import org.springframework.jdbc.core.ColumnMapRowMapper; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.transaction.PlatformTransactionManager; import javax.sql.DataSource; @@ -49,21 +50,21 @@ public Job sandNotificationAfterLessonJob(JobRepository jobRepository, PlatformT @Bean public Step sendNotificationBeforeClassStep( - JobRepository jobRepository, - PlatformTransactionManager transactionManager + final JobRepository jobRepository, + final PlatformTransactionManager transactionManager ) throws Exception { return new StepBuilder("addNotificationStep", jobRepository) ., Letter>chunk(CHUNK_SIZE, transactionManager) .reader(addNotificationItemReader()) .processor(addNotificationItemProcessor()) .writer(sendNotificationItemWriter) - .taskExecutor(new SimpleAsyncTaskExecutor()) + .taskExecutor(executor()) .build(); } @Bean public JdbcPagingItemReader> addNotificationItemReader() throws Exception { - Map parameterValues = new HashMap<>(); + final Map parameterValues = new HashMap<>(); parameterValues.put("endedAt", LocalDateTime.now()); return new JdbcPagingItemReaderBuilder>() @@ -83,7 +84,7 @@ private PagingQueryProvider createQueryProvider() throws Exception { queryProvider.setFromClause("FROM lesson l JOIN users u ON l.student_id = u.id JOIN users t ON l.teacher_id = t.id"); queryProvider.setWhereClause("WHERE l.ended_at <= :endedAt"); - Map sortKeys = new HashMap<>(1); + final Map sortKeys = new HashMap<>(1); sortKeys.put("l.ended_at", Order.ASCENDING); queryProvider.setSortKeys(sortKeys); @@ -100,4 +101,14 @@ public ItemProcessor, Letter> addNotificationItemProcessor() return Letter.of(studentToken, studentName, teacherName, endedAt, AFTER_LESSON); }; } + + @Bean + public TaskExecutor executor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(4); + executor.setWaitForTasksToCompleteOnShutdown(true); + executor.setAwaitTerminationSeconds(60); + executor.initialize(); + return executor; + } } diff --git a/doochul/src/main/java/org/doochul/job/SendNotificationBeforeLessonJobConfig.java b/doochul/src/main/java/org/doochul/job/SendNotificationBeforeLessonJobConfig.java index bb64ecc..355acb4 100644 --- a/doochul/src/main/java/org/doochul/job/SendNotificationBeforeLessonJobConfig.java +++ b/doochul/src/main/java/org/doochul/job/SendNotificationBeforeLessonJobConfig.java @@ -16,7 +16,9 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.core.task.TaskExecutor; import org.springframework.jdbc.core.ColumnMapRowMapper; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.transaction.PlatformTransactionManager; import javax.sql.DataSource; @@ -57,7 +59,7 @@ public Step sendNotificationBeforeLessonStep( .reader(addNotificationItemReader()) .processor(addNotificationItemProcessor()) .writer(sendNotificationItemWriter) - .taskExecutor(new SimpleAsyncTaskExecutor()) + .taskExecutor(executor()) .build(); } @@ -99,4 +101,14 @@ public ItemProcessor, Letter> addNotificationItemProcessor() return Letter.of(studentToken, studentName, teacherName, startedAt, BEFORE_LESSON); }; } + + @Bean + public TaskExecutor executor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(4); + executor.setWaitForTasksToCompleteOnShutdown(true); + executor.setAwaitTerminationSeconds(60); + executor.initialize(); + return executor; + } } From 09bd5e8a5a946a725451b0ca985494e463e2cb49 Mon Sep 17 00:00:00 2001 From: ingpyo Date: Mon, 11 Mar 2024 21:05:59 +0900 Subject: [PATCH 16/16] =?UTF-8?q?feat:=20=ED=8E=98=ED=82=A4=EC=A7=80=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99(service=20->=20application)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{service => application}/MessageSendManager.java | 4 +++- .../NotificationEventListener.java | 4 +++- .../{service => application}/NotificationService.java | 10 ++++++---- .../event}/LessonCreateEvent.java | 2 +- .../event}/LessonWithdrawnEvent.java | 2 +- .../org/doochul/domain/lesson/LessonRepository.java | 1 + .../{service => domain/lesson}/LessonStatus.java | 9 ++++----- .../main/java/org/doochul/infra/FcmMessageSender.java | 4 ++-- .../org/doochul/{service => infra/dto}/Letter.java | 4 +++- .../job/SendNotificationAfterLessonJobConfig.java | 4 ++-- .../job/SendNotificationBeforeLessonJobConfig.java | 5 ++--- .../org/doochul/job/SendNotificationItemWriter.java | 4 ++-- .../java/org/doochul/service/LessonStatusTest.java | 2 ++ .../org/doochul/service/NotificationServiceTest.java | 2 ++ 14 files changed, 34 insertions(+), 23 deletions(-) rename doochul/src/main/java/org/doochul/{service => application}/MessageSendManager.java (52%) rename doochul/src/main/java/org/doochul/{service => application}/NotificationEventListener.java (83%) rename doochul/src/main/java/org/doochul/{service => application}/NotificationService.java (83%) rename doochul/src/main/java/org/doochul/{service => application/event}/LessonCreateEvent.java (82%) rename doochul/src/main/java/org/doochul/{service => application/event}/LessonWithdrawnEvent.java (82%) rename doochul/src/main/java/org/doochul/{service => domain/lesson}/LessonStatus.java (94%) rename doochul/src/main/java/org/doochul/{service => infra/dto}/Letter.java (87%) diff --git a/doochul/src/main/java/org/doochul/service/MessageSendManager.java b/doochul/src/main/java/org/doochul/application/MessageSendManager.java similarity index 52% rename from doochul/src/main/java/org/doochul/service/MessageSendManager.java rename to doochul/src/main/java/org/doochul/application/MessageSendManager.java index 9845d1b..c965f87 100644 --- a/doochul/src/main/java/org/doochul/service/MessageSendManager.java +++ b/doochul/src/main/java/org/doochul/application/MessageSendManager.java @@ -1,4 +1,6 @@ -package org.doochul.service; +package org.doochul.application; + +import org.doochul.infra.dto.Letter; public interface MessageSendManager { void sendTo(final Letter letter); diff --git a/doochul/src/main/java/org/doochul/service/NotificationEventListener.java b/doochul/src/main/java/org/doochul/application/NotificationEventListener.java similarity index 83% rename from doochul/src/main/java/org/doochul/service/NotificationEventListener.java rename to doochul/src/main/java/org/doochul/application/NotificationEventListener.java index d76f5d1..3bc2cf1 100644 --- a/doochul/src/main/java/org/doochul/service/NotificationEventListener.java +++ b/doochul/src/main/java/org/doochul/application/NotificationEventListener.java @@ -1,7 +1,9 @@ -package org.doochul.service; +package org.doochul.application; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.doochul.application.event.LessonCreateEvent; +import org.doochul.application.event.LessonWithdrawnEvent; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; diff --git a/doochul/src/main/java/org/doochul/service/NotificationService.java b/doochul/src/main/java/org/doochul/application/NotificationService.java similarity index 83% rename from doochul/src/main/java/org/doochul/service/NotificationService.java rename to doochul/src/main/java/org/doochul/application/NotificationService.java index 0958bb1..0be0f89 100644 --- a/doochul/src/main/java/org/doochul/service/NotificationService.java +++ b/doochul/src/main/java/org/doochul/application/NotificationService.java @@ -1,18 +1,20 @@ -package org.doochul.service; +package org.doochul.application; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.doochul.application.RedisService; import org.doochul.domain.lesson.Lesson; import org.doochul.domain.user.User; +import org.doochul.application.event.LessonCreateEvent; +import org.doochul.application.event.LessonWithdrawnEvent; +import org.doochul.infra.dto.Letter; import org.doochul.support.KeyGenerator; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.time.Duration; -import static org.doochul.service.LessonStatus.SCHEDULED_LESSON; -import static org.doochul.service.LessonStatus.WITHDRAWN_LESSON; +import static org.doochul.domain.lesson.LessonStatus.SCHEDULED_LESSON; +import static org.doochul.domain.lesson.LessonStatus.WITHDRAWN_LESSON; @Slf4j @Service diff --git a/doochul/src/main/java/org/doochul/service/LessonCreateEvent.java b/doochul/src/main/java/org/doochul/application/event/LessonCreateEvent.java similarity index 82% rename from doochul/src/main/java/org/doochul/service/LessonCreateEvent.java rename to doochul/src/main/java/org/doochul/application/event/LessonCreateEvent.java index 9b5fbb2..9408cd2 100644 --- a/doochul/src/main/java/org/doochul/service/LessonCreateEvent.java +++ b/doochul/src/main/java/org/doochul/application/event/LessonCreateEvent.java @@ -1,4 +1,4 @@ -package org.doochul.service; +package org.doochul.application.event; import org.doochul.domain.lesson.Lesson; import org.doochul.domain.user.User; diff --git a/doochul/src/main/java/org/doochul/service/LessonWithdrawnEvent.java b/doochul/src/main/java/org/doochul/application/event/LessonWithdrawnEvent.java similarity index 82% rename from doochul/src/main/java/org/doochul/service/LessonWithdrawnEvent.java rename to doochul/src/main/java/org/doochul/application/event/LessonWithdrawnEvent.java index d240bdf..98be74b 100644 --- a/doochul/src/main/java/org/doochul/service/LessonWithdrawnEvent.java +++ b/doochul/src/main/java/org/doochul/application/event/LessonWithdrawnEvent.java @@ -1,4 +1,4 @@ -package org.doochul.service; +package org.doochul.application.event; import org.doochul.domain.lesson.Lesson; import org.doochul.domain.user.User; diff --git a/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java b/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java index fb3fe1b..af34bc6 100644 --- a/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java +++ b/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java @@ -11,4 +11,5 @@ default Lesson getById(final Long id) { } List findByStartedAtBefore(final LocalDateTime currentServerTime); + List findOngoingLessons(final LocalDateTime now); } diff --git a/doochul/src/main/java/org/doochul/service/LessonStatus.java b/doochul/src/main/java/org/doochul/domain/lesson/LessonStatus.java similarity index 94% rename from doochul/src/main/java/org/doochul/service/LessonStatus.java rename to doochul/src/main/java/org/doochul/domain/lesson/LessonStatus.java index e47b77f..d5c5c0a 100644 --- a/doochul/src/main/java/org/doochul/service/LessonStatus.java +++ b/doochul/src/main/java/org/doochul/domain/lesson/LessonStatus.java @@ -1,4 +1,6 @@ -package org.doochul.service; +package org.doochul.domain.lesson; + +import lombok.Getter; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -18,6 +20,7 @@ public enum LessonStatus { (name, time, teacher) -> formatToLocalTime(time) + " " + name + "님 " + teacher + " 강사님의 수업을 철회했습니다."), END_LESSON("수업 종료", (name, time, teacher) -> teacher + " 강사님의 수업이 모두 종료되었습니다."); + @Getter private final String title; private final LessonStatusMessage message; @@ -30,10 +33,6 @@ private static String formatToLocalTime(LocalDateTime time) { return time.format(DateTimeFormatter.ofPattern("a HH시 mm분")); } - public String getTitle() { - return title; - } - public String getMessage(String name, LocalDateTime time, String teacher) { return message.getMessage(name, time, teacher); } diff --git a/doochul/src/main/java/org/doochul/infra/FcmMessageSender.java b/doochul/src/main/java/org/doochul/infra/FcmMessageSender.java index d600580..3e2c406 100644 --- a/doochul/src/main/java/org/doochul/infra/FcmMessageSender.java +++ b/doochul/src/main/java/org/doochul/infra/FcmMessageSender.java @@ -9,8 +9,8 @@ import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.doochul.service.Letter; -import org.doochul.service.MessageSendManager; +import org.doochul.infra.dto.Letter; +import org.doochul.application.MessageSendManager; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Component; diff --git a/doochul/src/main/java/org/doochul/service/Letter.java b/doochul/src/main/java/org/doochul/infra/dto/Letter.java similarity index 87% rename from doochul/src/main/java/org/doochul/service/Letter.java rename to doochul/src/main/java/org/doochul/infra/dto/Letter.java index b096ba5..69ad912 100644 --- a/doochul/src/main/java/org/doochul/service/Letter.java +++ b/doochul/src/main/java/org/doochul/infra/dto/Letter.java @@ -1,4 +1,6 @@ -package org.doochul.service; +package org.doochul.infra.dto; + +import org.doochul.domain.lesson.LessonStatus; import java.time.LocalDateTime; diff --git a/doochul/src/main/java/org/doochul/job/SendNotificationAfterLessonJobConfig.java b/doochul/src/main/java/org/doochul/job/SendNotificationAfterLessonJobConfig.java index 102100f..bd69b4a 100644 --- a/doochul/src/main/java/org/doochul/job/SendNotificationAfterLessonJobConfig.java +++ b/doochul/src/main/java/org/doochul/job/SendNotificationAfterLessonJobConfig.java @@ -1,6 +1,6 @@ package org.doochul.job; -import org.doochul.service.Letter; +import org.doochul.infra.dto.Letter; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.job.builder.JobBuilder; @@ -26,7 +26,7 @@ import java.util.Map; import java.util.Optional; -import static org.doochul.service.LessonStatus.AFTER_LESSON; +import static org.doochul.domain.lesson.LessonStatus.AFTER_LESSON; @Configuration public class SendNotificationAfterLessonJobConfig { diff --git a/doochul/src/main/java/org/doochul/job/SendNotificationBeforeLessonJobConfig.java b/doochul/src/main/java/org/doochul/job/SendNotificationBeforeLessonJobConfig.java index 355acb4..0e87e9d 100644 --- a/doochul/src/main/java/org/doochul/job/SendNotificationBeforeLessonJobConfig.java +++ b/doochul/src/main/java/org/doochul/job/SendNotificationBeforeLessonJobConfig.java @@ -1,6 +1,6 @@ package org.doochul.job; -import org.doochul.service.Letter; +import org.doochul.infra.dto.Letter; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.job.builder.JobBuilder; @@ -15,7 +15,6 @@ import org.springframework.batch.item.database.support.SqlPagingQueryProviderFactoryBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.task.SimpleAsyncTaskExecutor; import org.springframework.core.task.TaskExecutor; import org.springframework.jdbc.core.ColumnMapRowMapper; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; @@ -27,7 +26,7 @@ import java.util.Map; import java.util.Optional; -import static org.doochul.service.LessonStatus.BEFORE_LESSON; +import static org.doochul.domain.lesson.LessonStatus.BEFORE_LESSON; @Configuration public class SendNotificationBeforeLessonJobConfig { diff --git a/doochul/src/main/java/org/doochul/job/SendNotificationItemWriter.java b/doochul/src/main/java/org/doochul/job/SendNotificationItemWriter.java index 158f3bc..6ad1e63 100644 --- a/doochul/src/main/java/org/doochul/job/SendNotificationItemWriter.java +++ b/doochul/src/main/java/org/doochul/job/SendNotificationItemWriter.java @@ -1,8 +1,8 @@ package org.doochul.job; import lombok.extern.slf4j.Slf4j; -import org.doochul.service.Letter; -import org.doochul.service.MessageSendManager; +import org.doochul.infra.dto.Letter; +import org.doochul.application.MessageSendManager; import org.springframework.batch.item.Chunk; import org.springframework.batch.item.ItemWriter; import org.springframework.stereotype.Component; diff --git a/doochul/src/test/java/org/doochul/service/LessonStatusTest.java b/doochul/src/test/java/org/doochul/service/LessonStatusTest.java index f8f0b9d..79899b0 100644 --- a/doochul/src/test/java/org/doochul/service/LessonStatusTest.java +++ b/doochul/src/test/java/org/doochul/service/LessonStatusTest.java @@ -4,6 +4,8 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; + +import org.doochul.domain.lesson.LessonStatus; import org.junit.jupiter.api.Test; class LessonStatusTest { diff --git a/doochul/src/test/java/org/doochul/service/NotificationServiceTest.java b/doochul/src/test/java/org/doochul/service/NotificationServiceTest.java index 4af016f..23ffedb 100644 --- a/doochul/src/test/java/org/doochul/service/NotificationServiceTest.java +++ b/doochul/src/test/java/org/doochul/service/NotificationServiceTest.java @@ -1,6 +1,8 @@ package org.doochul.service; +import org.doochul.application.MessageSendManager; import org.doochul.application.RedisService; +import org.doochul.infra.dto.Letter; import org.doochul.support.KeyGenerator; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired;