distribution-completed Kafka 이벤트 형식 변경

- DistributedChannelInfo DTO 추가 (channel, channelType, status, expectedViews)
- ChannelType enum에 category 필드 추가 (TV, CALL, SNS 구분)
- DistributionCompletedEvent 구조 변경 (distributedChannels를 상세 정보 리스트로 변경)
- completedAt 필드에 @JsonFormat 추가하여 ISO 8601 문자열 형식으로 직렬화
- publishDistributionCompletedEvent 메서드 수정하여 새로운 형식으로 이벤트 발행

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
sunmingLee 2025-10-29 09:56:32 +09:00
parent 828a76b630
commit 64aec0fda5
5 changed files with 67 additions and 30 deletions

View File

@ -7,20 +7,26 @@ package com.kt.distribution.dto;
* @since 2025-10-23 * @since 2025-10-23
*/ */
public enum ChannelType { public enum ChannelType {
URIDONGNETV("우리동네TV"), URIDONGNETV("우리동네TV", "TV"),
RINGOBIZ("링고비즈"), RINGOBIZ("링고비즈", "CALL"),
GINITV("지니TV"), GINITV("지니TV", "TV"),
INSTAGRAM("Instagram"), INSTAGRAM("Instagram", "SNS"),
NAVER("Naver Blog"), NAVER("Naver Blog", "SNS"),
KAKAO("Kakao Channel"); KAKAO("Kakao Channel", "SNS");
private final String displayName; private final String displayName;
private final String category;
ChannelType(String displayName) { ChannelType(String displayName, String category) {
this.displayName = displayName; this.displayName = displayName;
this.category = category;
} }
public String getDisplayName() { public String getDisplayName() {
return displayName; return displayName;
} }
public String getCategory() {
return category;
}
} }

View File

@ -0,0 +1,40 @@
package com.kt.distribution.event;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 배포된 채널 정보
* Kafka 이벤트에 포함되는 채널별 상세 정보
*
* @author System Architect
* @since 2025-10-29
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DistributedChannelInfo {
/**
* 채널명 (: "우리동네TV", "지니TV", "링고비즈")
*/
private String channel;
/**
* 채널 타입 (: "TV", "CALL", "SNS")
*/
private String channelType;
/**
* 배포 상태 (SUCCESS, FAILED)
*/
private String status;
/**
* 예상 조회수
*/
private Integer expectedViews;
}

View File

@ -1,5 +1,6 @@
package com.kt.distribution.event; package com.kt.distribution.event;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
@ -27,22 +28,13 @@ public class DistributionCompletedEvent {
private String eventId; private String eventId;
/** /**
* 배포 완료된 채널 목록 * 배포 완료된 채널 상세 정보 목록
*/ */
private List<String> distributedChannels; private List<DistributedChannelInfo> distributedChannels;
/** /**
* 배포 완료 시각 * 배포 완료 시각
*/ */
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSS")
private LocalDateTime completedAt; private LocalDateTime completedAt;
/**
* 성공한 채널
*/
private int successCount;
/**
* 실패한 채널
*/
private int failureCount;
} }

View File

@ -116,7 +116,7 @@ public class DistributionService {
saveCompletedStatus(request.getEventId(), results, startedAt, completedAt, successCount, failureCount); saveCompletedStatus(request.getEventId(), results, startedAt, completedAt, successCount, failureCount);
// Kafka Event 발행 // Kafka Event 발행
// publishDistributionCompletedEvent(request.getEventId(), results); publishDistributionCompletedEvent(request.getEventId(), results);
// 응답 생성 // 응답 생성
return DistributionResponse.builder() return DistributionResponse.builder()
@ -244,20 +244,19 @@ public class DistributionService {
return; return;
} }
List<String> distributedChannels = results.stream() List<com.kt.distribution.event.DistributedChannelInfo> distributedChannels = results.stream()
.filter(ChannelDistributionResult::isSuccess) .map(result -> com.kt.distribution.event.DistributedChannelInfo.builder()
.map(result -> result.getChannel().name()) .channel(result.getChannel().getDisplayName())
.channelType(result.getChannel().getCategory())
.status(result.isSuccess() ? "SUCCESS" : "FAILED")
.expectedViews(result.getEstimatedReach())
.build())
.collect(Collectors.toList()); .collect(Collectors.toList());
long successCount = results.stream().filter(ChannelDistributionResult::isSuccess).count();
long failureCount = results.size() - successCount;
DistributionCompletedEvent event = DistributionCompletedEvent.builder() DistributionCompletedEvent event = DistributionCompletedEvent.builder()
.eventId(eventId) .eventId(eventId)
.distributedChannels(distributedChannels) .distributedChannels(distributedChannels)
.completedAt(LocalDateTime.now()) .completedAt(LocalDateTime.now())
.successCount((int) successCount)
.failureCount((int) failureCount)
.build(); .build();
kafkaEventPublisher.get().publishDistributionCompleted(event); kafkaEventPublisher.get().publishDistributionCompleted(event);

View File

@ -36,8 +36,8 @@ public class KafkaEventPublisher {
*/ */
public void publishDistributionCompleted(DistributionCompletedEvent event) { public void publishDistributionCompleted(DistributionCompletedEvent event) {
try { try {
log.info("Publishing DistributionCompletedEvent: eventId={}, successCount={}, failureCount={}", log.info("Publishing DistributionCompletedEvent: eventId={}, channels={}",
event.getEventId(), event.getSuccessCount(), event.getFailureCount()); event.getEventId(), event.getDistributedChannels().size());
CompletableFuture<SendResult<String, Object>> future = CompletableFuture<SendResult<String, Object>> future =
kafkaTemplate.send(distributionCompletedTopic, event.getEventId(), event); kafkaTemplate.send(distributionCompletedTopic, event.getEventId(), event);