Skip to content

Commit

Permalink
#538 [feat] 모임당 인기글/ 인기 작가 로직 수정
Browse files Browse the repository at this point in the history
#538 [feat] 모임당 인기글/ 인기 작가 로직 수정
  • Loading branch information
sohyundoh authored Oct 20, 2024
2 parents 0f76e3c + 6e15bab commit cf006aa
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 47 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
./module-external/src/main/java/com/mile/aws/utils/S3Service merge=ours
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ public class CacheConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCaffeine(caffeineConfig());
cacheManager
.setAllowNullValues(false);
cacheManager
.setCaffeine(caffeineConfig());
return cacheManager;
}

Expand All @@ -32,7 +35,7 @@ private Scheduler getScheduler() {
private Caffeine<Object, Object> caffeineConfig() {
return Caffeine.newBuilder()
.maximumSize(200)
.expireAfterAccess(5, TimeUnit.DAYS)
.expireAfterAccess(1, TimeUnit.DAYS)
.scheduler(getScheduler());
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package com.mile.moim.repository;

import com.mile.moim.domain.popular.MoimPopularInfo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.Repository;
import org.springframework.scheduling.annotation.Scheduled;

import java.util.Optional;

public interface MoimPopularInfoRepository extends Repository<MoimPopularInfo, Long> {
public interface MoimPopularInfoRepository extends JpaRepository<MoimPopularInfo, Long> {

Optional<MoimPopularInfo> findByMoimId(final long moimId);

MoimPopularInfo save(final MoimPopularInfo moimPopularInfo);

@Scheduled(cron = "59 59 23 * * SUN")
void deleteAll();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ public class MoimService {
private final MoimRetriever moimRetriever;
private final MoimCreator moimCreator;
private final WriterNameRemover writerNameRemover;
private final CuriousRetriever curiousRetriever;
private final TopicRemover topicRemover;
private final TopicRetriever topicRetriever;
private final TopicCreator topicCreator;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.mile.moim.service.lock;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AtomicValidateMoimPopulerInfo {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.mile.moim.service.lock;

import com.mile.exception.message.ErrorMessage;
import com.mile.exception.model.MileException;
import com.mile.moim.domain.Moim;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Aspect
@RequiredArgsConstructor
@Component
public class MoimPopularInfoAspect {

private final RedissonClient redissonClient;
private final static String MOIM_POPULAR_LOCK = "MOIM_POPULAR_LOCK : ";
private final AopForTransaction aopForTransaction;

@Pointcut("@annotation(com.mile.moim.service.lock.AtomicValidateMoimPopulerInfo)")
public void setMoimPoplarInfoCut() {
}

@Around("setMoimPoplarInfoCut()")
public Object getLockForPopularInfoTransaction(final ProceedingJoinPoint joinPoint) throws Throwable {
final Moim moim = (Moim) joinPoint.getArgs()[0];

final RLock lock = redissonClient.getLock(MOIM_POPULAR_LOCK + moim.getId().toString());

try {
checkAvailability(lock.tryLock(3, 4, TimeUnit.SECONDS));
return aopForTransaction.proceed(joinPoint);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}

public void checkAvailability(final Boolean available) {
if (!available) throw new MileException(ErrorMessage.TIME_OUT_EXCEPTION);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.mile.moim.service.popular;

import com.mile.curious.repository.dto.PostAndCuriousCountInLastWeek;
import com.mile.curious.service.CuriousRetriever;
import com.mile.moim.domain.Moim;
import com.mile.moim.domain.popular.MoimCuriousPost;
import com.mile.moim.domain.popular.MoimCuriousWriter;
import com.mile.moim.domain.popular.MoimPopularInfo;
import com.mile.moim.repository.MoimPopularInfoRepository;
import com.mile.moim.service.lock.AtomicValidateMoimPopulerInfo;
import com.mile.writername.domain.WriterName;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CachePut;
import org.springframework.stereotype.Component;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Component
public class MoimPopularInfoRegister {
private final MoimPopularInfoRepository moimPopularInfoRepository;

private final CuriousRetriever curiousRetriever;


private List<MoimCuriousPost> getMoimCuriousPost(final List<PostAndCuriousCountInLastWeek> mostCuriousPostsInLastWeek) {
return mostCuriousPostsInLastWeek.stream().map(p ->
MoimCuriousPost.of(p.getPost())).limit(2).toList();
}

private List<MoimCuriousWriter> getMoimCuriousWriter(final List<PostAndCuriousCountInLastWeek> mostCuriousPostsInLastWeek) {
Map<WriterName, Long> writerNameCount = mostCuriousPostsInLastWeek.stream()
.collect(Collectors.groupingBy(p -> p.getPost().getWriterName(), Collectors.summingLong(PostAndCuriousCountInLastWeek::getCount)));

List<WriterName> topTwoWriters = writerNameCount.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.limit(2)
.map(Map.Entry::getKey).toList();

return topTwoWriters.stream().map(MoimCuriousWriter::of).toList();
}

@CachePut(value = "moimPopularInfo", key = "#moim.id")
@AtomicValidateMoimPopulerInfo
public MoimPopularInfo setMostPopularInfoOfMoim(final Moim moim) {
List<PostAndCuriousCountInLastWeek> mostCuriousPostsInLastWeek = curiousRetriever.findMostCuriousPostsInLastWeek(moim);

List<MoimCuriousPost> moimCuriousPosts = getMoimCuriousPost(mostCuriousPostsInLastWeek);

List<MoimCuriousWriter> moimCuriousWriters = getMoimCuriousWriter(mostCuriousPostsInLastWeek);

MoimPopularInfo moimPopularInfo = MoimPopularInfo.of(moim.getId(), moimCuriousPosts, moimCuriousWriters);

return moimPopularInfoRepository.saveAndFlush(moimPopularInfo);
}

}
Original file line number Diff line number Diff line change
@@ -1,63 +1,24 @@
package com.mile.moim.service.popular;

import com.mile.curious.repository.dto.PostAndCuriousCountInLastWeek;
import com.mile.curious.service.CuriousRetriever;
import com.mile.moim.domain.Moim;
import com.mile.moim.domain.popular.MoimCuriousPost;
import com.mile.moim.domain.popular.MoimCuriousWriter;
import com.mile.moim.domain.popular.MoimPopularInfo;
import com.mile.moim.repository.MoimPopularInfoRepository;
import com.mile.writername.domain.WriterName;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
public class MoimPopularInfoService {
private final MoimPopularInfoRepository moimPopularInfoRepository;
private final CuriousRetriever curiousRetriever;

@CachePut(value = "moimPopularInfo", key = "#moim.id")
public MoimPopularInfo setMostPopularInfoOfMoim(final Moim moim) {
List<PostAndCuriousCountInLastWeek> mostCuriousPostsInLastWeek = curiousRetriever.findMostCuriousPostsInLastWeek(moim);

List<MoimCuriousPost> moimCuriousPosts = getMoimCuriousPost(mostCuriousPostsInLastWeek);

List<MoimCuriousWriter> moimCuriousWriters = getMoimCuriousWriter(mostCuriousPostsInLastWeek);

MoimPopularInfo moimPopularInfo = MoimPopularInfo.of(moim.getId(), moimCuriousPosts, moimCuriousWriters);

return moimPopularInfoRepository.save(moimPopularInfo);
}

private List<MoimCuriousPost> getMoimCuriousPost(final List<PostAndCuriousCountInLastWeek> mostCuriousPostsInLastWeek) {
return mostCuriousPostsInLastWeek.stream().map(p ->
MoimCuriousPost.of(p.getPost())).limit(2).toList();
}
private final MoimPopularInfoRegister moimPopularInfoRegister;

private List<MoimCuriousWriter> getMoimCuriousWriter(final List<PostAndCuriousCountInLastWeek> mostCuriousPostsInLastWeek) {
Map<WriterName, Long> writerNameCount = mostCuriousPostsInLastWeek.stream()
.collect(Collectors.groupingBy(p -> p.getPost().getWriterName(), Collectors.summingLong(PostAndCuriousCountInLastWeek::getCount)));

List<WriterName> topTwoWriters = writerNameCount.entrySet().stream()
.sorted(Map.Entry.comparingByValue())
.limit(2)
.map(Map.Entry::getKey).toList();

return topTwoWriters.stream().map(MoimCuriousWriter::of).toList();
}

@Cacheable(value = "moimPopularInfo", key = "#moim.id")
public MoimPopularInfo getMoimPopularInfo(final Moim moim) {
return moimPopularInfoRepository.findByMoimId(moim.getId()).orElseGet(
() -> setMostPopularInfoOfMoim(moim)
() -> moimPopularInfoRegister.setMostPopularInfoOfMoim(moim)
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
@Component
public class S3Service {

private static final Long PRE_SIGNED_URL_EXPIRE_MINUTE = 120L; // 만료시간 2시간
private static final Long PRE_SIGNED_URL_EXPIRE_MINUTE = 1L; // 만료시간 2시간

private final String bucketName;
private final AwsConfig awsConfig;
Expand Down

0 comments on commit cf006aa

Please sign in to comment.