-
Notifications
You must be signed in to change notification settings - Fork 2
캐시 처리에 대한 표준화 객체 추가 및 학생 정원 수 관리 로직 추가 #133
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
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
cb2fbbb
MOSU chore: ExamQuota 관련 클래스 및 상태 추가
polyglot-k 3b2b5a6
MOSU chore: ApplicationQueryRepository, RefundQueryRepository, Studen…
polyglot-k 3587cd9
MOSU chore: Cache 관련 인터페이스(CacheEvictor, CacheLoader, CacheReader, Ca…
polyglot-k bdefa34
MOSU chore: RedisCache 관련 클래스(DefaultRedisCacheEvictor, DefaultRedisC…
polyglot-k 3103fac
MOSU chore: KeyValueCacheManager 추상 클래스 추가
polyglot-k 15a0bf1
MOSU chore: ExamQuotaCacheManager 클래스 리팩토링 및 캐시 메서드 추가
polyglot-k 4cf6339
MOSU chore: ExamQuotaEventListener 클래스 추가 및 이벤트 처리 메서드 구현
polyglot-k 6414d8b
MOSU chore: SwaggerConfig에서 서버 목록을 List.of()로 리팩토링
polyglot-k f5ff372
MOSU chore: ExamQuotaService 및 ExamQuotaEventResolver 클래스 추가 및 이벤트 처리…
polyglot-k 5330d2a
MOSU chore: ExamQuotaEventType에서 CURRENT_APPLICATION 및 MAX_CAPACITY의 …
polyglot-k 6a26113
MOSU chore: DefaultRedisCacheReader에서 read 메서드의 null 처리 개선
polyglot-k 77e83d3
MOSU chore: ExamService에서 ExamQuotaEvent 임포트 위치 수정
polyglot-k f2f15b4
chore: Update MAX_CAPACITY event status to include MaxCapacityStatus.…
polyglot-k File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
121 changes: 69 additions & 52 deletions
121
src/main/java/life/mosu/mosuserver/application/exam/ExamQuotaCacheManager.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,79 +1,96 @@ | ||
| package life.mosu.mosuserver.application.exam; | ||
|
|
||
| import java.time.LocalDate; | ||
| import java.util.List; | ||
| import life.mosu.mosuserver.domain.exam.ExamJpaEntity; | ||
| import java.util.Optional; | ||
| import life.mosu.mosuserver.domain.exam.ExamJpaRepository; | ||
| import life.mosu.mosuserver.domain.exam.projection.SchoolExamCountProjection; | ||
| import life.mosu.mosuserver.infra.persistence.redis.CacheLoader; | ||
| import life.mosu.mosuserver.infra.persistence.redis.CacheReader; | ||
| import life.mosu.mosuserver.infra.persistence.redis.CacheWriter; | ||
| import life.mosu.mosuserver.infra.persistence.redis.KeyValueCacheManager; | ||
| import lombok.Getter; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.data.redis.core.RedisTemplate; | ||
| import org.springframework.stereotype.Service; | ||
| import lombok.extern.slf4j.Slf4j; | ||
| import org.springframework.stereotype.Component; | ||
|
|
||
| @Service | ||
| @RequiredArgsConstructor | ||
| public class ExamQuotaCacheManager { | ||
| @Component | ||
| @Slf4j | ||
| public class ExamQuotaCacheManager extends KeyValueCacheManager<String, Long> { | ||
| private final ExamJpaRepository examJpaRepository; | ||
|
|
||
| private static final String REDIS_KEY_SCHOOL_MAX_CAPACITY = "school:max_capacity:"; | ||
| private static final String REDIS_KEY_SCHOOL_CURRENT_APPLICATIONS = "school:current_applications:"; | ||
| public ExamQuotaCacheManager( | ||
| CacheLoader<String, Long> cacheLoader, | ||
| CacheWriter<String, Long> cacheWriter, | ||
| CacheReader<String, Long> cacheReader, | ||
| ExamJpaRepository examJpaRepository | ||
| ) { | ||
| super(cacheLoader, cacheWriter, cacheReader); | ||
| this.examJpaRepository = examJpaRepository; | ||
| } | ||
|
|
||
| private final RedisTemplate<String, Long> redisTemplate; | ||
| private final ExamJpaRepository examJpaRepository; | ||
| public Optional<Long> getMaxCapacity(String schoolName) { | ||
| String key = ExamQuotaPrefix.MAX_CAPACITY.with(schoolName); | ||
| return cacheReader.read(key); | ||
| } | ||
|
|
||
| public void cacheSchoolMaxCapacities() { | ||
| List<ExamJpaEntity> exams = examJpaRepository.findUpcomingExamInfo(LocalDate.now()); | ||
| for (ExamJpaEntity exam : exams) { | ||
| addSchoolMaxCapacity( | ||
| exam.getSchoolName(), | ||
| exam.getCapacity() | ||
| ); | ||
| } | ||
| public Optional<Long> getCurrentApplications(String schoolName) { | ||
| String key = ExamQuotaPrefix.CURRENT_APPLICATIONS.with(schoolName); | ||
| return cacheReader.read(key); | ||
| } | ||
|
|
||
| public void cacheSchoolCurrentApplicationCounts() { | ||
| List<SchoolExamCountProjection> schoolExamCounts = examJpaRepository.countApplicationsGroupedBySchoolName(); | ||
| for (SchoolExamCountProjection projection : schoolExamCounts) { | ||
| addSchoolCurrentApplicationCount( | ||
| projection.schoolName(), | ||
| projection.applicationCount() | ||
| ); | ||
| } | ||
| public void setMaxCapacity(String schoolName, Long maxCapacity) { | ||
| String key = ExamQuotaPrefix.MAX_CAPACITY.with(schoolName); | ||
| cacheWriter.writeOrUpdate(key, maxCapacity); | ||
| } | ||
|
|
||
| public void addSchoolMaxCapacity(String schoolName, Integer capacity) { | ||
| String key = REDIS_KEY_SCHOOL_MAX_CAPACITY + schoolName; | ||
| redisTemplate.opsForValue().set(key, Long.valueOf(capacity)); | ||
| public void setCurrentApplications(String schoolName, Long currentApplications) { | ||
| String key = ExamQuotaPrefix.CURRENT_APPLICATIONS.with(schoolName); | ||
| cacheWriter.writeOrUpdate(key, currentApplications); | ||
| } | ||
|
|
||
| public void addSchoolCurrentApplicationCount(String schoolName, Long currentCount) { | ||
| String key = REDIS_KEY_SCHOOL_CURRENT_APPLICATIONS + schoolName; | ||
| redisTemplate.opsForValue().set(key, currentCount); | ||
| public void deleteMaxCapacity(String schoolName) { | ||
| String key = ExamQuotaPrefix.MAX_CAPACITY.with(schoolName); | ||
| cacheWriter.delete(key); | ||
| } | ||
|
|
||
| public Long getSchoolApplicationCounts(String schoolName) { | ||
| return redisTemplate.opsForValue() | ||
| .get(REDIS_KEY_SCHOOL_CURRENT_APPLICATIONS + schoolName); | ||
| public void deleteCurrentApplications(String schoolName) { | ||
| String key = ExamQuotaPrefix.CURRENT_APPLICATIONS.with(schoolName); | ||
| cacheWriter.delete(key); | ||
| } | ||
|
|
||
| public Long getSchoolCapacities(String schoolName) { | ||
| return redisTemplate.opsForValue() | ||
| .get(REDIS_KEY_SCHOOL_MAX_CAPACITY + schoolName); | ||
| public void increaseCurrentApplications(String schoolName) { | ||
| String key = ExamQuotaPrefix.CURRENT_APPLICATIONS.with(schoolName); | ||
| cacheWriter.increase(key); | ||
| } | ||
|
|
||
| public void increaseApplicationCount(String schoolName) { | ||
| String key = REDIS_KEY_SCHOOL_CURRENT_APPLICATIONS + schoolName; | ||
| redisTemplate.opsForValue().increment(key); | ||
| public void decreaseCurrentApplications(String schoolName) { | ||
| String key = ExamQuotaPrefix.CURRENT_APPLICATIONS.with(schoolName); | ||
| cacheWriter.decrease(key); | ||
| } | ||
|
|
||
| public void decreaseApplicationCount(String schoolName) { | ||
| String key = REDIS_KEY_SCHOOL_CURRENT_APPLICATIONS + schoolName; | ||
| Long currentValue = redisTemplate.opsForValue().get(key); | ||
| if (currentValue != null && currentValue > 0) { | ||
| redisTemplate.opsForValue().decrement(key); | ||
| } | ||
| @Override | ||
| protected void initCache() { | ||
| examJpaRepository.findUpcomingExamInfo(LocalDate.now()) | ||
| .forEach(exam -> setMaxCapacity( | ||
| exam.getSchoolName(), | ||
| exam.getCapacity().longValue() | ||
| )); | ||
| examJpaRepository.countApplicationsGroupedBySchoolName() | ||
| .forEach(projection -> setCurrentApplications( | ||
| projection.schoolName(), | ||
| projection.applicationCount() | ||
| )); | ||
| } | ||
polyglot-k marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| public void preloadSchoolData() { | ||
| cacheSchoolMaxCapacities(); | ||
| cacheSchoolCurrentApplicationCounts(); | ||
| @RequiredArgsConstructor | ||
| @Getter | ||
| private enum ExamQuotaPrefix { | ||
| MAX_CAPACITY("school:max_capacity:"), | ||
| CURRENT_APPLICATIONS("school:current_applications:"); | ||
|
|
||
| private final String prefix; | ||
|
|
||
| public String with(String schoolName) { | ||
| return prefix + schoolName; | ||
| } | ||
| } | ||
| } | ||
19 changes: 19 additions & 0 deletions
19
src/main/java/life/mosu/mosuserver/application/exam/ExamQuotaService.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package life.mosu.mosuserver.application.exam; | ||
|
|
||
| import java.util.function.Consumer; | ||
| import life.mosu.mosuserver.application.exam.resolver.ExamQuotaEventResolver; | ||
| import life.mosu.mosuserver.presentation.exam.dto.event.ExamQuotaEvent; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.stereotype.Service; | ||
|
|
||
| @Service | ||
| @RequiredArgsConstructor | ||
| public class ExamQuotaService { | ||
|
|
||
| private final ExamQuotaEventResolver resolver; | ||
|
|
||
| public void handleExamQuotaEvent(ExamQuotaEvent event) { | ||
| Consumer<ExamQuotaEvent> handler = resolver.resolve(event); | ||
| handler.accept(event); | ||
| } | ||
polyglot-k marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
60 changes: 60 additions & 0 deletions
60
src/main/java/life/mosu/mosuserver/application/exam/resolver/ExamQuotaEventResolver.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| package life.mosu.mosuserver.application.exam.resolver; | ||
|
|
||
| import java.util.function.Consumer; | ||
| import life.mosu.mosuserver.application.exam.ExamQuotaCacheManager; | ||
| import life.mosu.mosuserver.presentation.exam.dto.event.ApplicationStatus; | ||
| import life.mosu.mosuserver.presentation.exam.dto.event.ExamQuotaEvent; | ||
| import life.mosu.mosuserver.presentation.exam.dto.event.MaxCapacityStatus; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.stereotype.Component; | ||
|
|
||
| @Component | ||
| @RequiredArgsConstructor | ||
| public class ExamQuotaEventResolver { | ||
|
|
||
| private final ExamQuotaCacheManager examQuotaCacheManager; | ||
|
|
||
| public Consumer<ExamQuotaEvent> resolve(ExamQuotaEvent event) { | ||
| return switch (event.getType()) { | ||
| case LOAD -> resolveLoad(event); | ||
| case DELETE_ALL -> resolveDeleteAll(event); | ||
| case CURRENT_APPLICATION -> resolveCurrentApplication(event); | ||
| case MAX_CAPACITY -> resolveMaxCapacity(event); | ||
| }; | ||
| } | ||
|
|
||
| private Consumer<ExamQuotaEvent> resolveLoad(ExamQuotaEvent event) { | ||
| return e -> { | ||
| examQuotaCacheManager.setMaxCapacity(e.getSchoolName(), e.getValue()); | ||
| examQuotaCacheManager.setCurrentApplications(e.getSchoolName(),0L); | ||
| }; | ||
| } | ||
| private Consumer<ExamQuotaEvent> resolveDeleteAll(ExamQuotaEvent event){ | ||
| return e -> { | ||
| examQuotaCacheManager.deleteMaxCapacity(e.getSchoolName()); | ||
| examQuotaCacheManager.deleteCurrentApplications(e.getSchoolName()); | ||
| }; | ||
| } | ||
| private Consumer<ExamQuotaEvent> resolveCurrentApplication(ExamQuotaEvent event) { | ||
| if (!(event.getStatus() instanceof ApplicationStatus status)) { | ||
| throw new IllegalArgumentException("Invalid status for CURRENT_APPLICATION event"); | ||
| } | ||
|
|
||
| return switch (status) { | ||
| case CREATE -> e -> examQuotaCacheManager.setCurrentApplications(e.getSchoolName(), e.getValue()); | ||
| case INCREASE -> e -> examQuotaCacheManager.increaseCurrentApplications(e.getSchoolName()); | ||
| case DECREASE -> e -> examQuotaCacheManager.decreaseCurrentApplications(e.getSchoolName()); | ||
| case DELETE -> e -> examQuotaCacheManager.deleteCurrentApplications(e.getSchoolName()); | ||
| }; | ||
| } | ||
polyglot-k marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| private Consumer<ExamQuotaEvent> resolveMaxCapacity(ExamQuotaEvent event) { | ||
| if (!(event.getStatus() instanceof MaxCapacityStatus status)) { | ||
| throw new IllegalArgumentException("Invalid status for MAX_CAPACITY event"); | ||
| } | ||
| return switch (status) { | ||
| case CREATE, UPDATE -> e -> examQuotaCacheManager.setMaxCapacity(e.getSchoolName(), e.getValue()); | ||
| case DELETE -> e -> examQuotaCacheManager.deleteMaxCapacity(e.getSchoolName()); | ||
| }; | ||
| } | ||
polyglot-k marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
19 changes: 0 additions & 19 deletions
19
src/main/java/life/mosu/mosuserver/global/runner/ApplicationSchoolPreWarmRunner.java
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 2 additions & 1 deletion
3
...main/admin/RefundQueryRepositoryImpl.java → ...stence/jpa/RefundQueryRepositoryImpl.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 5 additions & 0 deletions
5
src/main/java/life/mosu/mosuserver/infra/persistence/redis/CacheEvictor.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| package life.mosu.mosuserver.infra.persistence.redis; | ||
|
|
||
| public interface CacheEvictor<K> { | ||
| void evict(K key); | ||
| } |
11 changes: 11 additions & 0 deletions
11
src/main/java/life/mosu/mosuserver/infra/persistence/redis/CacheLoader.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package life.mosu.mosuserver.infra.persistence.redis; | ||
|
|
||
| import java.util.Map; | ||
|
|
||
| public interface CacheLoader<K,V> { | ||
| void loadAll(Map<K, V> values); | ||
|
|
||
| void load(K key, V value); | ||
|
|
||
| boolean exists(K key); | ||
| } | ||
polyglot-k marked this conversation as resolved.
Show resolved
Hide resolved
|
||
7 changes: 7 additions & 0 deletions
7
src/main/java/life/mosu/mosuserver/infra/persistence/redis/CacheReader.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package life.mosu.mosuserver.infra.persistence.redis; | ||
|
|
||
| import java.util.Optional; | ||
|
|
||
| public interface CacheReader<K,V> { | ||
| Optional<V> read(K key); | ||
| } |
8 changes: 8 additions & 0 deletions
8
src/main/java/life/mosu/mosuserver/infra/persistence/redis/CacheWriter.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package life.mosu.mosuserver.infra.persistence.redis; | ||
|
|
||
| public interface CacheWriter<K,V> { | ||
| void writeOrUpdate(K key, V value); | ||
| void increase(K key); | ||
| void decrease(K key); | ||
| void delete(K key); | ||
| } | ||
polyglot-k marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.