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

#538 [feat] 모임당 인기글/ 인기 작가 로직 수정 #543

Merged
merged 4 commits into from
Oct 20, 2024
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
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
Loading