Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] 알람 기능구현 및 spring batch를 사용한 스케줄기능 구현 #13

Merged
merged 17 commits into from
Mar 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
bfaf0ec
feat: Batch 설정 및 user엔티티 재정
ingpyo Mar 10, 2024
ae32fec
feat: Batch를 사용해 수업전 리마인드 알람 스케줄 작성
ingpyo Mar 10, 2024
a8621ff
feat: Batch를 사용해 수업전 리마인드 알람 스케줄 작성(JPA -> 쿼리로 변경)
ingpyo Mar 10, 2024
91d64c1
feat: Batch를 사용해 수업후 알람 및 이용권 개수 차감
ingpyo Mar 10, 2024
52af19f
feat: job을 실행시키는 스케줄러 구현
ingpyo Mar 10, 2024
aee1e2d
feat: batch로 스케줄 로직 이동 및 클래스 네이밍 오타 수정
ingpyo Mar 11, 2024
1b91c41
feat: TaskExecutor 설정
ingpyo Mar 11, 2024
81cde92
feat: 페키지 이동(service -> application)
ingpyo Mar 11, 2024
fc7f46c
feat: Batch 설정 및 user엔티티 재정
ingpyo Mar 10, 2024
3268caf
feat: Batch를 사용해 수업전 리마인드 알람 스케줄 작성
ingpyo Mar 10, 2024
e82ad16
feat: Batch를 사용해 수업전 리마인드 알람 스케줄 작성(JPA -> 쿼리로 변경)
ingpyo Mar 10, 2024
c28296f
feat: Batch를 사용해 수업후 알람 및 이용권 개수 차감
ingpyo Mar 10, 2024
df92357
feat: job을 실행시키는 스케줄러 구현
ingpyo Mar 10, 2024
d4f8655
feat: batch로 스케줄 로직 이동 및 클래스 네이밍 오타 수정
ingpyo Mar 11, 2024
8a1cdce
feat: TaskExecutor 설정
ingpyo Mar 11, 2024
09bd5e8
feat: 페키지 이동(service -> application)
ingpyo Mar 11, 2024
50d7d2a
Merge remote-tracking branch 'origin/feat/12-schedule-logic-spring-ba…
ingpyo Mar 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions doochul/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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'
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.doochul.application;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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.domain.lesson.LessonStatus.SCHEDULED_LESSON;
import static org.doochul.domain.lesson.LessonStatus.WITHDRAWN_LESSON;

@Slf4j
@Service
@RequiredArgsConstructor
public class NotificationService {
private final MessageSendManager messageSendManager;
private final KeyGenerator keyGenerator;
private final RedisService redisService;

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.getDeviceToken(),
student.getName(),
teacher.getName(),
lesson.getStartedAt(),
SCHEDULED_LESSON));
}

public void withdrawnForLessons(final LessonWithdrawnEvent event) {
sendNotification(
Letter.of(event.student().getDeviceToken(),
event.student().getName(),
event.teacher().getName(),
event.lesson().getStartedAt(),
WITHDRAWN_LESSON));
}

@Async
public void sendNotification(final Letter letter) {
final String key = keyGenerator.generateAccountKey(letter.targetToken());
if (redisService.setNX(key, "notification", Duration.ofSeconds(5))) {
messageSendManager.sendTo(letter);
redisService.delete(key);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
8 changes: 0 additions & 8 deletions doochul/src/main/java/org/doochul/config/AppConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
}
}
23 changes: 23 additions & 0 deletions doochul/src/main/java/org/doochul/config/AsyncConfig.java
Original file line number Diff line number Diff line change
@@ -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(4);
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
executor.initialize();
return executor;
}
}
19 changes: 19 additions & 0 deletions doochul/src/main/java/org/doochul/config/BatchConfig.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
24 changes: 24 additions & 0 deletions doochul/src/main/java/org/doochul/domain/lesson/Lesson.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ default Lesson getById(final Long id) {
}

List<Lesson> findByStartedAtBefore(final LocalDateTime currentServerTime);
List<Lesson> findOngoingLessons(final LocalDateTime now);
}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;

Expand All @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand Down
7 changes: 7 additions & 0 deletions doochul/src/main/java/org/doochul/domain/product/Product.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,11 @@ 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;
}
}
Original file line number Diff line number Diff line change
@@ -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<Product, Long> {
List<Product> findAll();
public interface ProductRepository extends JpaRepository<ProductRepository, Long> {
}
15 changes: 14 additions & 1 deletion doochul/src/main/java/org/doochul/domain/user/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.doochul.domain.BaseEntity;

@Entity
Expand All @@ -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;
}
}
4 changes: 2 additions & 2 deletions doochul/src/main/java/org/doochul/infra/FcmMessageSender.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
22 changes: 22 additions & 0 deletions doochul/src/main/java/org/doochul/infra/dto/Letter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.doochul.infra.dto;

import org.doochul.domain.lesson.LessonStatus;

import java.time.LocalDateTime;

public record Letter(
String targetToken,
String title,
String body
) {
public static Letter of(
final String studentToken,
final String studentName,
final String teacherName,
final LocalDateTime startedAt,
final LessonStatus lessonStatus
) {
final String message = lessonStatus.getMessage(studentName, startedAt, teacherName);
return new Letter(studentToken, lessonStatus.getTitle(), message);
}
}
Loading