-
Notifications
You must be signed in to change notification settings - Fork 0
[refactor] 피드 저장 시 일급컬렉션이 아닌 boolean으로 저장 여부 조회 #250
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
Changes from all commits
4808e87
84f6311
03b4249
c4bde19
c349c2d
d11416c
5199172
0ac4b6d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -68,7 +68,9 @@ jobs: | |||||||||||
| cd ${{ env.COMPOSE_PATH }} | ||||||||||||
|
|
||||||||||||
| echo "✋🏻Stopping existing container and Cleaning up old images" | ||||||||||||
| sudo docker-compose down --rmi all | ||||||||||||
| # sudo docker-compose down --rmi all | ||||||||||||
| sudo docker-compose stop ${{ secrets.DOCKER_IMAGE }} | ||||||||||||
| sudo docker rm -f ${{ secrets.DOCKER_IMAGE }} | ||||||||||||
|
Comment on lines
+71
to
+73
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. YAML 블록 들여쓰기 오류 + 잘못된 대상(이미지명)으로 컨테이너 중지/삭제 시도
단순하고 안전한 방법은 compose 프로젝트 단위로 컨테이너를 중지/정리하는 것입니다. 아래처럼 교체하면:
적용 제안: -# sudo docker-compose down --rmi all
- sudo docker-compose stop ${{ secrets.DOCKER_IMAGE }}
- sudo docker rm -f ${{ secrets.DOCKER_IMAGE }}
+ # docker-compose down --rmi all # 이미지는 유지하고 컨테이너만 교체합니다 (이미지는 아래 prune에서 정리)
+ sudo docker-compose down --remove-orphans참고:
📝 Committable suggestion
Suggested change
🧰 Tools🪛 YAMLlint (1.37.1)[error] 72-72: syntax error: expected , but found '' (syntax) 🤖 Prompt for AI Agents |
||||||||||||
|
|
||||||||||||
| sudo docker ps -a | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,16 +1,18 @@ | ||
| package konkuk.thip.feed.application.service; | ||
|
|
||
| import konkuk.thip.common.exception.BusinessException; | ||
| import konkuk.thip.feed.application.port.in.FeedSavedUseCase; | ||
| import konkuk.thip.feed.application.port.in.dto.FeedIsSavedCommand; | ||
| import konkuk.thip.feed.application.port.in.dto.FeedIsSavedResult; | ||
| import konkuk.thip.feed.application.port.out.FeedCommandPort; | ||
| import konkuk.thip.feed.application.port.out.FeedQueryPort; | ||
| import konkuk.thip.feed.domain.Feed; | ||
| import konkuk.thip.feed.domain.SavedFeeds; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.stereotype.Service; | ||
| import org.springframework.transaction.annotation.Transactional; | ||
|
|
||
| import static konkuk.thip.common.exception.code.ErrorCode.*; | ||
|
|
||
| @Service | ||
| @RequiredArgsConstructor | ||
| public class FeedSavedService implements FeedSavedUseCase { | ||
|
|
@@ -20,24 +22,31 @@ public class FeedSavedService implements FeedSavedUseCase { | |
|
|
||
| @Override | ||
| @Transactional | ||
| public FeedIsSavedResult changeSavedFeed(FeedIsSavedCommand feedIsSavedCommand) { | ||
| public FeedIsSavedResult changeSavedFeed(FeedIsSavedCommand command) { | ||
|
|
||
| // 1. 피드 검증 및 조회 | ||
| Feed feed = feedCommandPort.getByIdOrThrow(feedIsSavedCommand.feedId()); | ||
| Feed feed = feedCommandPort.getByIdOrThrow(command.feedId()); | ||
|
|
||
| // 2. 유저가 저장한 피드 목록 조회 | ||
| SavedFeeds savedFeeds = feedQueryPort.findSavedFeedsByUserId(feedIsSavedCommand.userId()); | ||
| // 2. 유저가 해당 피드를 저장했는지 여부 조회 | ||
| boolean alreadySaved = feedQueryPort.existsSavedFeedByUserIdAndFeedId(command.userId(), feed.getId()); | ||
| validateSaveFeedAction(command.isSaved(), alreadySaved); | ||
|
Comment on lines
+30
to
+32
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 굳굳 |
||
|
|
||
| if (feedIsSavedCommand.isSaved()) { | ||
| // 저장 요청 시 이미 저장되어 있으면 예외 발생 | ||
| savedFeeds.validateNotAlreadySaved(feed); | ||
| feedCommandPort.saveSavedFeed(feedIsSavedCommand.userId(), feed.getId()); | ||
| if (command.isSaved()) { | ||
| feedCommandPort.saveSavedFeed(command.userId(), feed.getId()); | ||
| } else { | ||
| // 삭제 요청 시 저장되어 있지 않으면 예외 발생 | ||
| savedFeeds.validateCanDelete(feed); | ||
| feedCommandPort.deleteSavedFeed(feedIsSavedCommand.userId(), feed.getId()); | ||
| feedCommandPort.deleteSavedFeed(command.userId(), feed.getId()); | ||
| } | ||
|
|
||
| return FeedIsSavedResult.of(feed.getId(), feedIsSavedCommand.isSaved()); | ||
| return FeedIsSavedResult.of(feed.getId(), command.isSaved()); | ||
| } | ||
|
Comment on lines
+25
to
+41
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chaincheck-then-act 경쟁 상태 가능성: 유니크 제약 및 예외 매핑으로 보강 권장 현재 플로우는
형태의 check-then-act 패턴입니다. 동시 요청이 들어오면, 존재 여부 확인 직후 상태가 바뀌는 경쟁 상태가 발생할 수 있습니다. 이를 안전하게 만들기 위해 다음을 권장합니다. 필수 보강(권장 구현):
예시 패치: @@
- if (command.isSaved()) {
- feedCommandPort.saveSavedFeed(command.userId(), feed.getId());
- } else {
- feedCommandPort.deleteSavedFeed(command.userId(), feed.getId());
- }
+ if (command.isSaved()) {
+ try {
+ feedCommandPort.saveSavedFeed(command.userId(), feed.getId());
+ } catch (org.springframework.dao.DataIntegrityViolationException e) {
+ // 동시성 등으로 인한 중복 저장 시도를 비즈니스 예외로 변환
+ throw new BusinessException(FEED_ALREADY_SAVED);
+ }
+ } else {
+ // 사전 검증으로 not-saved 삭제는 방지되나, 동시성으로 사라진 경우도 고려하여
+ // deleteSavedFeed 구현이 영향 행 수를 반환한다면 체크/로깅을 고려할 수 있습니다.
+ feedCommandPort.deleteSavedFeed(command.userId(), feed.getId());
+ }또한, SavedFeed 테이블에 유니크 인덱스가 없으면 위 보강만으로는 완전하지 않습니다. 아래 스크립트로 유니크 제약 및 예외 매핑 유무를 확인해 주세요. 필요 시 후속 PR에서 제약 추가/예외 매핑을 도와드릴 수 있습니다. 🏁 Script executed: #!/bin/bash
# SavedFeed 유니크 제약 및 저장/삭제 구현에서의 예외 매핑 여부 확인
echo "== SavedFeedJpaEntity 정의 위치 =="
rg -n "class\s+SavedFeedJpaEntity\b" -C2
echo
echo "== @Table(uniqueConstraints=...), unique=true 등 유니크 제약 여부 =="
rg -n "@Table\(" -C2
rg -n "uniqueConstraints" -C2
rg -n "unique\s*=\s*true" -C2
echo
echo "== saveSavedFeed/deleteSavedFeed 구현 및 예외 매핑 흔적 =="
rg -n "saveSavedFeed\s*\(" -C3
rg -n "deleteSavedFeed\s*\(" -C3
rg -n "DataIntegrityViolationException|DuplicateKeyException|FEED_ALREADY_SAVED|FEED_NOT_SAVED_CANNOT_DELETE" -C2Length of output: 21004 DB 유니크 제약 및 예외 처리 보강 필요 현재 SavedFeed 엔티티에는 (user_id, feed_id) 복합 유니크 제약이 없고, 저장 로직에서도 동시 중복 저장 시 발생하는 예외를 잡아 변환하는 처리가 빠져 있습니다. 경쟁 상태를 방지하고 최종 일관성을 보장하기 위해 아래와 같이 반영을 권장합니다.
위 보강 작업 후, FeedChangeSavedApiTest에서 중복 저장/삭제 시나리오가 여전히 올바르게 동작하는지 재검증해주세요. 🤖 Prompt for AI Agents |
||
|
|
||
| private void validateSaveFeedAction(boolean isSaveRequest, boolean alreadySaved) { | ||
| if (isSaveRequest && alreadySaved) { | ||
| // 이미 저장되어 있는 피드를 다시 저장하려는 경우 예외 처리 | ||
| throw new BusinessException(FEED_ALREADY_SAVED); | ||
| } else if (!isSaveRequest && !alreadySaved) { | ||
| // 저장되지 않은 피드를 삭제하려는 경우 예외 처리 | ||
| throw new BusinessException(FEED_NOT_SAVED_CANNOT_DELETE); | ||
| } | ||
|
Comment on lines
+43
to
+50
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 굿굿 깔끔쓰하네여 |
||
| } | ||
| } | ||
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
굳굳 기존 컨테이너 강제로 내리면 개발서버가 좀 더 안정화될수도 있겠네요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
기존에는 mysql redis까지 모두 내렸다가 다시 올렸는데 생각해보니 두 컨테이너는 굳이 내릴 필요가 없다고 판단해서 그냥 서버 컨테이너만 내렸다가 올리려고 합니다!