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
Expand Up @@ -145,7 +145,12 @@ public void scheduleForPost(Post post) {
}

@Transactional
public void scheduleReplyForAiComment(Comment aiComment, Post post) {
public void scheduleReplyForAiComment(Long aiCommentId, Long postId) {
Comment aiComment = commentRepository.findById(aiCommentId).orElse(null);
if (aiComment == null) {
return;
}
Comment on lines +148 to +152

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

postId 파라미터는 불필요해 보입니다. aiComment 엔티티가 이미 Post에 대한 참조를 가지고 있으므로 이를 활용할 수 있습니다. 또한, 이벤트 리스너를 통해 전달된 ID로 엔티티를 조회할 때 데이터가 없는 것은 정상적인 상황이 아닐 가능성이 높으므로, 단순히 return 하기보다 orElseThrow를 통해 명시적인 예외를 던져 관측성을 높이는 것이 좋습니다.

    public void scheduleReplyForAiComment(Long aiCommentId) {
        Comment aiComment = commentRepository.findById(aiCommentId)
                .orElseThrow(() -> new NotFoundException("AI 댓글을 찾을 수 없습니다. id=" + aiCommentId));


if (aiComment.getAiReplyCount() >= MAX_AI_REPLY_COUNT) {
return;
}
Expand All @@ -160,6 +165,11 @@ public void scheduleReplyForAiComment(Comment aiComment, Post post) {
return;
}

Post post = postRepository.findById(postId).orElse(null);
if (post == null) {
return;
}
Comment on lines +168 to +171

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

앞서 언급한 대로 aiComment.getPost()를 사용하면 별도의 DB 조회 없이 게시물 엔티티에 접근할 수 있습니다. JPA 프록시를 활용하면 불필요한 SELECT 쿼리 발생도 방지할 수 있어 더 효율적입니다.

Suggested change
Post post = postRepository.findById(postId).orElse(null);
if (post == null) {
return;
}
Post post = aiComment.getPost();


aiComment.incrementAiReplyCount();

Instant scheduledAt = Instant.now().plusSeconds(replyDelayMinutes * 60L);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.daramg.server.aicomment.event;

public record AiReplyScheduleEvent(
Long aiCommentId,
Long postId
) {
Comment on lines +3 to +6

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

AiCommentService에서 aiCommentId만으로 필요한 정보를 모두 가져올 수 있게 되었으므로, 이벤트 객체에서도 불필요한 postId 필드를 제거하는 것이 좋습니다.

public record AiReplyScheduleEvent(
        Long aiCommentId
) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.daramg.server.aicomment.event;

import com.daramg.server.aicomment.application.AiCommentService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionalEventListener;

import static org.springframework.transaction.event.TransactionPhase.AFTER_COMMIT;

@Slf4j
@Component
@RequiredArgsConstructor
public class AiReplyScheduleEventListener {

private final AiCommentService aiCommentService;

@TransactionalEventListener(phase = AFTER_COMMIT)
public void handleAiReplyScheduleEvent(AiReplyScheduleEvent event) {
try {
aiCommentService.scheduleReplyForAiComment(event.aiCommentId(), event.postId());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

서비스 메서드 시그니처 변경에 맞춰 호출부를 수정해야 합니다.

Suggested change
aiCommentService.scheduleReplyForAiComment(event.aiCommentId(), event.postId());
aiCommentService.scheduleReplyForAiComment(event.aiCommentId());

} catch (Exception e) {
log.warn("AI 답글 잡 등록 실패 - aiCommentId={}, postId={}", event.aiCommentId(), event.postId(), e);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.daramg.server.comment.application;

import com.daramg.server.aicomment.application.AiCommentService;
import com.daramg.server.aicomment.event.AiReplyScheduleEvent;
import com.daramg.server.comment.domain.Comment;
import com.daramg.server.comment.domain.CommentLike;
import com.daramg.server.comment.dto.CommentLikeResponseDto;
Expand Down Expand Up @@ -30,7 +30,6 @@ public class CommentService {
private final CommentRepository commentRepository;
private final CommentLikeRepository commentLikeRepository;
private final ApplicationEventPublisher eventPublisher;
private final AiCommentService aiCommentService;

public void createComment(Long postId, CommentCreateDto request, User user){
Post post = entityUtils.getEntity(postId, Post.class);
Expand Down Expand Up @@ -80,7 +79,7 @@ public void createReply(Long commentId, CommentReplyCreateDto request, User user
}

if (parentComment.isAi()) {
aiCommentService.scheduleReplyForAiComment(parentComment, post);
eventPublisher.publishEvent(new AiReplyScheduleEvent(parentComment.getId(), post.getId()));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

이벤트 생성 시 불필요한 post.getId() 전달을 제거합니다.

Suggested change
eventPublisher.publishEvent(new AiReplyScheduleEvent(parentComment.getId(), post.getId()));
eventPublisher.publishEvent(new AiReplyScheduleEvent(parentComment.getId()));

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,14 +220,14 @@ class ScheduleReplyTest {
commentRepository.save(aiComment);

// when
aiCommentService.scheduleReplyForAiComment(aiComment, post);
aiCommentService.scheduleReplyForAiComment(aiComment.getId(), post.getId());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

서비스 메서드 시그니처 변경에 맞춰 테스트 코드를 수정합니다.

Suggested change
aiCommentService.scheduleReplyForAiComment(aiComment.getId(), post.getId());
aiCommentService.scheduleReplyForAiComment(aiComment.getId());


// then
List<AiCommentJob> jobs = aiCommentJobRepository.findAll();
assertThat(jobs).hasSize(1);
assertThat(jobs.get(0).getTriggerType()).isEqualTo(AiCommentJobTriggerType.USER_REPLY);
assertThat(jobs.get(0).getParentComment().getId()).isEqualTo(aiComment.getId());
assertThat(aiComment.getAiReplyCount()).isEqualTo((byte) 1);
assertThat(commentRepository.findById(aiComment.getId()).get().getAiReplyCount()).isEqualTo((byte) 1);
}

@Test
Expand All @@ -240,9 +240,10 @@ class ScheduleReplyTest {
Comment aiComment = Comment.ofAi(post, botUser, "AI 댓글", null, composer);
commentRepository.save(aiComment);
ReflectionTestUtils.setField(aiComment, "aiReplyCount", (byte) 2);
commentRepository.save(aiComment);

// when
aiCommentService.scheduleReplyForAiComment(aiComment, post);
aiCommentService.scheduleReplyForAiComment(aiComment.getId(), post.getId());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

서비스 메서드 시그니처 변경에 맞춰 테스트 코드를 수정합니다.

Suggested change
aiCommentService.scheduleReplyForAiComment(aiComment.getId(), post.getId());
aiCommentService.scheduleReplyForAiComment(aiComment.getId());


// then
assertThat(aiCommentJobRepository.findAll()).isEmpty();
Expand Down
Loading