Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -1,29 +1,18 @@
package com.TwoSeaU.BaData.domain.rental.event;

import static org.springframework.transaction.annotation.Propagation.REQUIRES_NEW;

import com.TwoSeaU.BaData.domain.rental.entity.DeviceReservation;
import com.TwoSeaU.BaData.domain.rental.entity.ReStock;
import com.TwoSeaU.BaData.domain.rental.entity.Reservation;
import com.TwoSeaU.BaData.domain.rental.repository.DeviceReservationRepository;
import com.TwoSeaU.BaData.domain.rental.repository.ReStockRepository;
import com.TwoSeaU.BaData.domain.store.entity.StoreDevice;
import com.TwoSeaU.BaData.domain.store.exception.StoreException;
import com.TwoSeaU.BaData.domain.rental.service.RestockDeleteTargetingService;
import com.TwoSeaU.BaData.domain.user.entity.FcmToken;
import com.TwoSeaU.BaData.domain.user.entity.User;
import com.TwoSeaU.BaData.domain.user.repository.FcmTokenRepository;
import com.TwoSeaU.BaData.global.email.MailService;
import com.TwoSeaU.BaData.global.fcm.FCMService;
import com.TwoSeaU.BaData.global.fcm.dto.NotificationRequest;
import com.TwoSeaU.BaData.global.response.GeneralException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;

Expand All @@ -34,20 +23,19 @@ public class RentalListenerEvent {

private final MailService mailService;
private final FCMService fcmService;
private final ReStockRepository reStockRepository;
private final DeviceReservationRepository deviceReservationRepository;
private final RestockDeleteTargetingService restockDeleteTargetingService;
private final FcmTokenRepository fcmTokenRepository;
private static final String restockTitle = "찜한 와이파이 왔어요!";
private static final String restockContent = " 지금 아니면 또 놓칠지도 몰라요, 파도처럼 \uD83C\uDF0A";

@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
@Transactional(propagation = REQUIRES_NEW)
@Async("threadPoolTaskExecutor")
public void restockEventListener(final RestockEvent restockEvent){
Comment thread
dionisos198 marked this conversation as resolved.

final List<User> sendTargetUser = getSendTargetUser(restockEvent.getReservation(), restockEvent.getDeviceReservations());
final List<User> sendTargetUser = restockDeleteTargetingService.getSendTargetUser(restockEvent.getReservation(), restockEvent.getDeviceReservations());

sendEmail(sendTargetUser);
sendFcmToken(sendTargetUser);
sendEmail(sendTargetUser);
}

private void sendEmail(final List<User> sendTargetUsers){
Expand All @@ -66,40 +54,4 @@ private void sendFcmToken(final List<User> sendTargetUsers){

fcmService.sendToManyUser(NotificationRequest.forMultipleTokens(restockTitle, restockContent, fcmTokens, Map.of()));
}

private List<User> getSendTargetUser(final Reservation reservation, final List<DeviceReservation> deviceReservations) {

final List<User> sendUserTargets = new ArrayList<>();

final LocalDateTime rentalStart = reservation.getRentalStartDate();
final LocalDateTime rentalEnd = reservation.getRentalEndDate();

for(final DeviceReservation deviceReservation : deviceReservations){

final StoreDevice storeDevice = deviceReservation.getStoreDevice();

// 1. 취소된 예약 기간과 겹치는 알림 신청자만 조회
final List<ReStock> overlappedReStocks = reStockRepository.findOverlappedReStocks(
storeDevice, rentalStart, rentalEnd
);

for (final ReStock reStock : overlappedReStocks) {

// 2. 신청자의 희망 기간 동안의 남은 수량 계산
final Long availableCount = deviceReservationRepository.findAvailableCountsByStoreDeviceIdAndPeriod(storeDevice.getId(), rentalStart, rentalEnd)
.orElseThrow(()-> new GeneralException(StoreException.CANT_FIND_STORE_DEVICE));

log.info("AvailableCount: {}, Restock DesiredCount: {}", availableCount, reStock.getDesiredCount());

// 3. 남은 수량이 재입고 알림 수량 보다 큰 경우
if (availableCount >= reStock.getDesiredCount()) {
sendUserTargets.add(reStock.getUser());
reStockRepository.delete(reStock);
}
}

}

return sendUserTargets;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@
public interface ReStockRepository extends JpaRepository<ReStock,Long>, ReStockQueryRepository {

@Query("""
SELECT r FROM ReStock r
SELECT r FROM ReStock r join fetch r.user u
WHERE r.storeDevice = :storeDevice
AND r.desiredStartDate <= :rentalEndDate
AND r.desiredEndDate >= :rentalStartDate

""")
List<ReStock> findOverlappedReStocks(
@Param("storeDevice") StoreDevice storeDevice,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.TwoSeaU.BaData.domain.rental.service;

import com.TwoSeaU.BaData.domain.rental.entity.DeviceReservation;
import com.TwoSeaU.BaData.domain.rental.entity.ReStock;
import com.TwoSeaU.BaData.domain.rental.entity.Reservation;
import com.TwoSeaU.BaData.domain.rental.repository.DeviceReservationRepository;
import com.TwoSeaU.BaData.domain.rental.repository.ReStockRepository;
import com.TwoSeaU.BaData.domain.store.entity.StoreDevice;
import com.TwoSeaU.BaData.domain.store.exception.StoreException;
import com.TwoSeaU.BaData.domain.user.entity.User;
import com.TwoSeaU.BaData.global.response.GeneralException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Slf4j
public class RestockDeleteTargetingService {

private final ReStockRepository reStockRepository;
private final DeviceReservationRepository deviceReservationRepository;

@Transactional(propagation = Propagation.REQUIRES_NEW)
public List<User> getSendTargetUser(final Reservation reservation, final List<DeviceReservation> deviceReservations) {

final List<User> sendUserTargets = new ArrayList<>();

final LocalDateTime rentalStart = reservation.getRentalStartDate();
final LocalDateTime rentalEnd = reservation.getRentalEndDate();

for(final DeviceReservation deviceReservation : deviceReservations){

final StoreDevice storeDevice = deviceReservation.getStoreDevice();

// 1. 취소된 예약 기간과 겹치는 알림 신청자만 조회
final List<ReStock> overlappedReStocks = reStockRepository.findOverlappedReStocks(
storeDevice, rentalStart, rentalEnd
);

for (final ReStock reStock : overlappedReStocks) {

// 2. 신청자의 희망 기간 동안의 남은 수량 계산
final Long availableCount = deviceReservationRepository.findAvailableCountsByStoreDeviceIdAndPeriod(storeDevice.getId(), rentalStart, rentalEnd)
.orElseThrow(()-> new GeneralException(StoreException.CANT_FIND_STORE_DEVICE));
Comment thread
dionisos198 marked this conversation as resolved.

log.info("AvailableCount: {}, Restock DesiredCount: {}", availableCount, reStock.getDesiredCount());

// 3. 남은 수량이 재입고 알림 수량 보다 큰 경우
if (availableCount >= reStock.getDesiredCount()) {
sendUserTargets.add(reStock.getUser());
reStockRepository.delete(reStock);
}
Comment thread
dionisos198 marked this conversation as resolved.
}

Comment thread
dionisos198 marked this conversation as resolved.
}

return sendUserTargets;
}
Comment thread
dionisos198 marked this conversation as resolved.

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.TwoSeaU.BaData.global.fcm.dto.NotificationRequest;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
Expand All @@ -16,13 +17,13 @@ public class ReportListenerEvent {
private final MailService mailService;
private final FCMService fcmService;

@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
@EventListener
Comment thread
dionisos198 marked this conversation as resolved.
public void createReportEmailEventListener(final ReportEmailEvent reportEmailEvent){

mailService.sendMail(reportEmailEvent.getTargetEmail(), reportEmailEvent.getTitle(), reportEmailEvent.getContents());
}

@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
@EventListener
Comment thread
dionisos198 marked this conversation as resolved.
Comment thread
dionisos198 marked this conversation as resolved.
public void createReportFcmEventListener(final ReportFcmEvent reportFcmEvent){

fcmService.sendToManyUser(NotificationRequest.forMultipleTokens(reportFcmEvent.getTitle(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -31,6 +32,7 @@ public class ReportNotificationService {
private static long REPORT_THRESHOLD = 3;

@Transactional(readOnly = true)
Comment thread
dionisos198 marked this conversation as resolved.
@Async("threadPoolTaskExecutor")
public void sendReportNotification(final Report report){

final long reportCount = reportRepository.countByPost(report.getPost());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.TwoSeaU.BaData.global.config;

import java.util.concurrent.Executor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
@EnableAsync
public class SpringAsyncConfig {

@Bean(name = "threadPoolTaskExecutor")
public Executor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(100);
Comment thread
dionisos198 marked this conversation as resolved.
taskExecutor.setQueueCapacity(Integer.MAX_VALUE);
Comment thread
dionisos198 marked this conversation as resolved.
taskExecutor.setThreadNamePrefix("Executor-");
return taskExecutor;
}
Comment thread
dionisos198 marked this conversation as resolved.

}