Skip to content

Commit a5575ee

Browse files
authored
Merge pull request #17 from softeerbootcamp4th/feat/event-scheduling
[Feature] 선착순 이벤트 당첨자수 스케줄링
2 parents aba33b1 + 352608c commit a5575ee

12 files changed

+277
-4
lines changed

Diff for: .gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,5 @@ out/
3535

3636
### VS Code ###
3737
.vscode/
38+
39+
*.groovy
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.softeer.podoarrival.config;
2+
3+
import io.swagger.v3.oas.models.OpenAPI;
4+
import io.swagger.v3.oas.models.info.Info;
5+
import org.springframework.context.annotation.Bean;
6+
import org.springframework.context.annotation.Configuration;
7+
8+
//http://localhost:8081/swagger-ui/index.html
9+
@Configuration
10+
public class SwaggerConfig {
11+
12+
private final String TITLE = "Softeer-arrival";
13+
private final String DESCRIPTION = "못말리는 현기차 arrival-server swagger";
14+
private final String VERSION = "V1.0.0";
15+
16+
@Bean
17+
public OpenAPI api() {
18+
return new OpenAPI()
19+
.info(new Info()
20+
.title(TITLE)
21+
.description(DESCRIPTION)
22+
.version(VERSION)
23+
);
24+
}
25+
26+
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.softeer.podoarrival.event.exception;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Getter;
5+
6+
@AllArgsConstructor
7+
@Getter
8+
public class EventTypeNotExistsException extends RuntimeException {
9+
private String message;
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.softeer.podoarrival.event.model.entity;
2+
3+
import com.fasterxml.jackson.annotation.JsonFormat;
4+
import com.softeer.podoarrival.common.entity.DateEntity;
5+
import jakarta.persistence.*;
6+
import lombok.AllArgsConstructor;
7+
import lombok.Builder;
8+
import lombok.Data;
9+
import lombok.NoArgsConstructor;
10+
11+
import java.time.LocalDateTime;
12+
import java.time.LocalTime;
13+
import java.util.List;
14+
15+
@Entity
16+
@Table(name = "events")
17+
@Data
18+
@Builder
19+
@AllArgsConstructor
20+
@NoArgsConstructor
21+
public class Event extends DateEntity {
22+
@Id
23+
@GeneratedValue(strategy = GenerationType.IDENTITY)
24+
@Column(name = "event_id")
25+
private Long id;
26+
27+
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
28+
@JoinColumn(name = "type_id")
29+
private EventType eventType;
30+
31+
private String title;
32+
private String description;
33+
34+
/**
35+
* 형식은 7자리 0과 1로 이루어진 문자열. 월화수목금토일 의미
36+
*/
37+
@Column(name = "repeat_day")
38+
private String repeatDay;
39+
@JsonFormat(pattern = "HH:mm:ss")
40+
@Column(name = "repeat_time")
41+
private LocalTime repeatTime;
42+
43+
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
44+
@Column(name = "start_time")
45+
private LocalDateTime startAt;
46+
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
47+
@Column(name = "end_time")
48+
private LocalDateTime endAt;
49+
50+
@Column(name = "tag_image")
51+
private String tagImage;
52+
53+
@OneToMany(mappedBy = "event" , orphanRemoval = true, cascade = CascadeType.ALL)
54+
private List<EventReward> eventRewardList;
55+
56+
@OneToOne(mappedBy = "event" , orphanRemoval = true, cascade = CascadeType.ALL)
57+
private EventWeight eventWeight;
58+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.softeer.podoarrival.event.model.entity;
2+
3+
import com.softeer.podoarrival.common.entity.DateEntity;
4+
import jakarta.persistence.*;
5+
import lombok.AllArgsConstructor;
6+
import lombok.Builder;
7+
import lombok.Data;
8+
import lombok.NoArgsConstructor;
9+
10+
11+
@Entity
12+
@Table(name = "event_rewards")
13+
@Data
14+
@Builder
15+
@AllArgsConstructor
16+
@NoArgsConstructor
17+
public class EventReward extends DateEntity {
18+
@Id
19+
@GeneratedValue(strategy = GenerationType.IDENTITY)
20+
@Column(name = "reward_id")
21+
private Long id;
22+
@Column(name = "reward_rank")
23+
private int rewardRank;
24+
/**
25+
* 당첨자수
26+
*/
27+
@Column(name = "winner_number")
28+
private int numWinners;
29+
private String reward;
30+
31+
@ManyToOne(fetch = FetchType.LAZY)
32+
@JoinColumn(name = "event_id")
33+
private Event event;
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.softeer.podoarrival.event.model.entity;
2+
3+
import com.softeer.podoarrival.common.entity.DateEntity;
4+
import jakarta.persistence.*;
5+
import lombok.AllArgsConstructor;
6+
import lombok.Builder;
7+
import lombok.Data;
8+
import lombok.NoArgsConstructor;
9+
10+
@Entity
11+
@Table(name = "event_types")
12+
@Data
13+
@Builder
14+
@AllArgsConstructor
15+
@NoArgsConstructor
16+
public class EventType extends DateEntity {
17+
@Id
18+
@GeneratedValue(strategy = GenerationType.IDENTITY)
19+
@Column(name = "type_id")
20+
private Long id;
21+
@Column(name = "type")
22+
private String type;
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.softeer.podoarrival.event.model.entity;
2+
3+
import com.softeer.podoarrival.common.entity.DateEntity;
4+
import jakarta.persistence.*;
5+
import lombok.AllArgsConstructor;
6+
import lombok.Builder;
7+
import lombok.Data;
8+
import lombok.NoArgsConstructor;
9+
10+
@Entity
11+
@Table(name = "event_weights")
12+
@Data
13+
@Builder
14+
@AllArgsConstructor
15+
@NoArgsConstructor
16+
public class EventWeight extends DateEntity {
17+
@Id
18+
@GeneratedValue(strategy = GenerationType.IDENTITY)
19+
@Column(name = "weight_id")
20+
private Long id;
21+
/**
22+
* 가중치 배수
23+
*/
24+
private int times;
25+
@Column(name = "weight_condition")
26+
private String weightCondition;
27+
28+
@OneToOne(fetch = FetchType.LAZY)
29+
@JoinColumn(name = "event_id")
30+
private Event event;
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.softeer.podoarrival.event.repository;
2+
3+
4+
import com.softeer.podoarrival.event.model.entity.Event;
5+
import com.softeer.podoarrival.event.model.entity.EventType;
6+
import org.springframework.data.jpa.repository.JpaRepository;
7+
8+
import java.time.LocalDateTime;
9+
import java.util.Optional;
10+
11+
public interface EventRepository extends JpaRepository<Event, Long> {
12+
/**
13+
* 이벤트 타입이 일치하고, startAt이 오늘인 이벤트 1개를 반환하는 메서드
14+
* @param eventType 이벤트 타입
15+
* @return 조건에 맞는 이벤트 (없으면 null)
16+
*/
17+
Event findFirstByEventTypeAndStartAtBetween(EventType eventType, LocalDateTime startAtStart, LocalDateTime startAtEnd);
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.softeer.podoarrival.event.repository;
2+
3+
import com.softeer.podoarrival.event.model.entity.Event;
4+
import com.softeer.podoarrival.event.model.entity.EventReward;
5+
import org.springframework.data.jpa.repository.JpaRepository;
6+
7+
public interface EventRewardRepository extends JpaRepository<EventReward, Long> {
8+
int countByEvent(Event event);
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.softeer.podoarrival.event.repository;
2+
3+
4+
import com.softeer.podoarrival.event.model.entity.EventType;
5+
import org.springframework.data.jpa.repository.JpaRepository;
6+
7+
public interface EventTypeRepository extends JpaRepository<EventType, Long> {
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.softeer.podoarrival.event.scheduler.scheduler;
2+
3+
import com.softeer.podoarrival.event.exception.EventTypeNotExistsException;
4+
import com.softeer.podoarrival.event.model.entity.Event;
5+
import com.softeer.podoarrival.event.model.entity.EventType;
6+
import com.softeer.podoarrival.event.repository.EventRepository;
7+
import com.softeer.podoarrival.event.repository.EventRewardRepository;
8+
import com.softeer.podoarrival.event.repository.EventTypeRepository;
9+
import com.softeer.podoarrival.event.service.ArrivalEventReleaseService;
10+
import lombok.RequiredArgsConstructor;
11+
import lombok.extern.slf4j.Slf4j;
12+
import org.springframework.scheduling.annotation.Scheduled;
13+
import org.springframework.stereotype.Component;
14+
15+
import java.time.LocalDate;
16+
import java.time.LocalDateTime;
17+
18+
/**
19+
* 선착순 이벤트의 당첨자 수를 세팅하는 스케줄러
20+
*/
21+
@Slf4j
22+
@Component
23+
@RequiredArgsConstructor
24+
public class ArrivalEventMaxArrivalScheduler {
25+
26+
private final EventRepository eventRepository;
27+
private final EventTypeRepository eventTypeRepository;
28+
private final EventRewardRepository eventRewardRepository;
29+
30+
/**
31+
* 특정 시간에 Mysql에서 금일 진행될 선착순 이벤트의 당첨자 수를 읽어옴
32+
*
33+
*/
34+
@Scheduled(cron = "0 25 03 * * *")
35+
public void setEventArrivalCount() {
36+
// 시작일자, 이벤트 종류만 고려하여 이벤트 추출
37+
LocalDateTime startOfDay = LocalDate.now().atStartOfDay();
38+
LocalDateTime endOfDay = startOfDay.plusDays(1).minusNanos(1);
39+
40+
// 선착순 이벤트
41+
EventType eventType = eventTypeRepository.findById(1L).orElseThrow(() -> new EventTypeNotExistsException("이벤트 타입이 존재하지 않습니다."));
42+
Event findEvent = eventRepository.findFirstByEventTypeAndStartAtBetween(eventType, startOfDay, endOfDay);
43+
44+
// 찾은 이벤트에 해당하는 reword개수 조회
45+
int rewordCount = eventRewardRepository.countByEvent(findEvent);
46+
47+
ArrivalEventReleaseService.setMaxArrival(rewordCount);
48+
}
49+
}

Diff for: src/main/java/com/softeer/podoarrival/event/service/ArrivalEventReleaseService.java

+8-4
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,17 @@
22

33
import com.softeer.podoarrival.event.exception.ExistingUserException;
44
import com.softeer.podoarrival.event.model.dto.ArrivalApplicationResponseDto;
5-
import com.softeer.podoarrival.security.AuthInfo;
65
import com.softeer.podoarrival.event.model.entity.ArrivalUser;
76
import com.softeer.podoarrival.event.model.entity.Role;
87
import com.softeer.podoarrival.event.repository.ArrivalUserRepository;
8+
import com.softeer.podoarrival.security.AuthInfo;
99
import lombok.RequiredArgsConstructor;
1010
import lombok.extern.slf4j.Slf4j;
1111
import org.redisson.api.BatchResult;
1212
import org.redisson.api.RBatch;
1313
import org.redisson.api.RedissonClient;
1414
import org.springframework.scheduling.annotation.Async;
15+
import org.springframework.scheduling.annotation.Scheduled;
1516
import org.springframework.stereotype.Service;
1617

1718
import java.time.LocalDate;
@@ -28,14 +29,14 @@ public class ArrivalEventReleaseService {
2829
private final String ARRIVAL_SET = "arrivalset";
2930
private boolean CHECK = false;
3031

31-
private final int MAX_ARRIVAL = 100;
32+
private static int MAX_ARRIVAL = 0;
3233

3334
/**
3435
* 비동기로 Redis 호출하는 메서드
3536
* 반환값은 ArrivalEventService에서 받아서 선착순 처리
3637
*/
3738
@Async("arrivalExecutor")
38-
public CompletableFuture<ArrivalApplicationResponseDto> applyEvent(AuthInfo authInfo){
39+
public CompletableFuture<ArrivalApplicationResponseDto> applyEvent(AuthInfo authInfo) {
3940
return CompletableFuture.supplyAsync(() -> {
4041
LocalDate now = LocalDate.now();
4142

@@ -51,7 +52,6 @@ public CompletableFuture<ArrivalApplicationResponseDto> applyEvent(AuthInfo auth
5152

5253
//첫번째 응답
5354
if(!(boolean) res.getResponses().get(0)){
54-
log.info("전화번호-중복 = {}", authInfo.getPhoneNum());
5555
throw new ExistingUserException("이미 응모한 전화번호입니다.");
5656
}
5757

@@ -73,4 +73,8 @@ public CompletableFuture<ArrivalApplicationResponseDto> applyEvent(AuthInfo auth
7373
}
7474
});
7575
}
76+
77+
public static void setMaxArrival(int val) {
78+
MAX_ARRIVAL = val;
79+
}
7680
}

0 commit comments

Comments
 (0)