Skip to content

Commit

Permalink
Merge pull request #17 from softeerbootcamp4th/feat/event-scheduling
Browse files Browse the repository at this point in the history
[Feature] 선착순 이벤트 당첨자수 스케줄링
  • Loading branch information
eckrin authored Aug 7, 2024
2 parents aba33b1 + 352608c commit a5575ee
Show file tree
Hide file tree
Showing 12 changed files with 277 additions and 4 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@ out/

### VS Code ###
.vscode/

*.groovy
27 changes: 27 additions & 0 deletions src/main/java/com/softeer/podoarrival/config/SwaggerConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.softeer.podoarrival.config;

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

//http://localhost:8081/swagger-ui/index.html
@Configuration
public class SwaggerConfig {

private final String TITLE = "Softeer-arrival";
private final String DESCRIPTION = "못말리는 현기차 arrival-server swagger";
private final String VERSION = "V1.0.0";

@Bean
public OpenAPI api() {
return new OpenAPI()
.info(new Info()
.title(TITLE)
.description(DESCRIPTION)
.version(VERSION)
);
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.softeer.podoarrival.event.exception;

import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
@Getter
public class EventTypeNotExistsException extends RuntimeException {
private String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.softeer.podoarrival.event.model.entity;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.softeer.podoarrival.common.entity.DateEntity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;

@Entity
@Table(name = "events")
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Event extends DateEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "event_id")
private Long id;

@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
@JoinColumn(name = "type_id")
private EventType eventType;

private String title;
private String description;

/**
* 형식은 7자리 0과 1로 이루어진 문자열. 월화수목금토일 의미
*/
@Column(name = "repeat_day")
private String repeatDay;
@JsonFormat(pattern = "HH:mm:ss")
@Column(name = "repeat_time")
private LocalTime repeatTime;

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Column(name = "start_time")
private LocalDateTime startAt;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Column(name = "end_time")
private LocalDateTime endAt;

@Column(name = "tag_image")
private String tagImage;

@OneToMany(mappedBy = "event" , orphanRemoval = true, cascade = CascadeType.ALL)
private List<EventReward> eventRewardList;

@OneToOne(mappedBy = "event" , orphanRemoval = true, cascade = CascadeType.ALL)
private EventWeight eventWeight;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.softeer.podoarrival.event.model.entity;

import com.softeer.podoarrival.common.entity.DateEntity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;


@Entity
@Table(name = "event_rewards")
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class EventReward extends DateEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "reward_id")
private Long id;
@Column(name = "reward_rank")
private int rewardRank;
/**
* 당첨자수
*/
@Column(name = "winner_number")
private int numWinners;
private String reward;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "event_id")
private Event event;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.softeer.podoarrival.event.model.entity;

import com.softeer.podoarrival.common.entity.DateEntity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Table(name = "event_types")
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class EventType extends DateEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "type_id")
private Long id;
@Column(name = "type")
private String type;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.softeer.podoarrival.event.model.entity;

import com.softeer.podoarrival.common.entity.DateEntity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Table(name = "event_weights")
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class EventWeight extends DateEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "weight_id")
private Long id;
/**
* 가중치 배수
*/
private int times;
@Column(name = "weight_condition")
private String weightCondition;

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "event_id")
private Event event;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.softeer.podoarrival.event.repository;


import com.softeer.podoarrival.event.model.entity.Event;
import com.softeer.podoarrival.event.model.entity.EventType;
import org.springframework.data.jpa.repository.JpaRepository;

import java.time.LocalDateTime;
import java.util.Optional;

public interface EventRepository extends JpaRepository<Event, Long> {
/**
* 이벤트 타입이 일치하고, startAt이 오늘인 이벤트 1개를 반환하는 메서드
* @param eventType 이벤트 타입
* @return 조건에 맞는 이벤트 (없으면 null)
*/
Event findFirstByEventTypeAndStartAtBetween(EventType eventType, LocalDateTime startAtStart, LocalDateTime startAtEnd);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.softeer.podoarrival.event.repository;

import com.softeer.podoarrival.event.model.entity.Event;
import com.softeer.podoarrival.event.model.entity.EventReward;
import org.springframework.data.jpa.repository.JpaRepository;

public interface EventRewardRepository extends JpaRepository<EventReward, Long> {
int countByEvent(Event event);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.softeer.podoarrival.event.repository;


import com.softeer.podoarrival.event.model.entity.EventType;
import org.springframework.data.jpa.repository.JpaRepository;

public interface EventTypeRepository extends JpaRepository<EventType, Long> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.softeer.podoarrival.event.scheduler.scheduler;

import com.softeer.podoarrival.event.exception.EventTypeNotExistsException;
import com.softeer.podoarrival.event.model.entity.Event;
import com.softeer.podoarrival.event.model.entity.EventType;
import com.softeer.podoarrival.event.repository.EventRepository;
import com.softeer.podoarrival.event.repository.EventRewardRepository;
import com.softeer.podoarrival.event.repository.EventTypeRepository;
import com.softeer.podoarrival.event.service.ArrivalEventReleaseService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.LocalDateTime;

/**
* 선착순 이벤트의 당첨자 수를 세팅하는 스케줄러
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class ArrivalEventMaxArrivalScheduler {

private final EventRepository eventRepository;
private final EventTypeRepository eventTypeRepository;
private final EventRewardRepository eventRewardRepository;

/**
* 특정 시간에 Mysql에서 금일 진행될 선착순 이벤트의 당첨자 수를 읽어옴
*
*/
@Scheduled(cron = "0 25 03 * * *")
public void setEventArrivalCount() {
// 시작일자, 이벤트 종류만 고려하여 이벤트 추출
LocalDateTime startOfDay = LocalDate.now().atStartOfDay();
LocalDateTime endOfDay = startOfDay.plusDays(1).minusNanos(1);

// 선착순 이벤트
EventType eventType = eventTypeRepository.findById(1L).orElseThrow(() -> new EventTypeNotExistsException("이벤트 타입이 존재하지 않습니다."));
Event findEvent = eventRepository.findFirstByEventTypeAndStartAtBetween(eventType, startOfDay, endOfDay);

// 찾은 이벤트에 해당하는 reword개수 조회
int rewordCount = eventRewardRepository.countByEvent(findEvent);

ArrivalEventReleaseService.setMaxArrival(rewordCount);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@

import com.softeer.podoarrival.event.exception.ExistingUserException;
import com.softeer.podoarrival.event.model.dto.ArrivalApplicationResponseDto;
import com.softeer.podoarrival.security.AuthInfo;
import com.softeer.podoarrival.event.model.entity.ArrivalUser;
import com.softeer.podoarrival.event.model.entity.Role;
import com.softeer.podoarrival.event.repository.ArrivalUserRepository;
import com.softeer.podoarrival.security.AuthInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.BatchResult;
import org.redisson.api.RBatch;
import org.redisson.api.RedissonClient;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

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

private final int MAX_ARRIVAL = 100;
private static int MAX_ARRIVAL = 0;

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

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

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

Expand All @@ -73,4 +73,8 @@ public CompletableFuture<ArrivalApplicationResponseDto> applyEvent(AuthInfo auth
}
});
}

public static void setMaxArrival(int val) {
MAX_ARRIVAL = val;
}
}

0 comments on commit a5575ee

Please sign in to comment.