본문으로 건너뛰기

이벤트 관리 명세

개요

이벤트 관리 명세는, TimeMachine이 시간 변경 시 발생시키는 이벤트의 형식, 처리 방법, 이벤트 흐름에 대한 상세 내용을 정의합니다. 이 명세는 가상 시간 변경 시 시스템 전체에 걸쳐 일관된 데이터와 동작을 보장하기 위한 것입니다.

이벤트 유형

TimeMachine에서 발생하는 주요 이벤트 유형은 다음과 같습니다:

이벤트 유형설명중요도
TIME_CHANGED시스템 가상 시간이 변경됨높음
USER_TIME_CHANGED특정 사용자의 가상 시간이 변경됨중간
TIME_RESET시스템 시간이 실제 시간으로 재설정됨높음
TIMEMACHINE_ENABLEDTimeMachine 기능이 활성화됨낮음
TIMEMACHINE_DISABLEDTimeMachine 기능이 비활성화됨낮음
ROLLBACK_INITIATED데이터 롤백이 시작됨높음
ROLLBACK_COMPLETED데이터 롤백이 완료됨중간
ROLLBACK_FAILED데이터 롤백이 실패함높음

이벤트 구조

1. 공통 이벤트 구조

모든 TimeMachine 이벤트는 다음과 같은 공통 구조를 갖습니다:

interface BaseTimeMachineEvent {
eventId: string; // 고유한 이벤트 ID (UUID)
eventType: string; // 이벤트 유형
source: string; // 이벤트 소스 (일반적으로 'time-machine')
timestamp: number; // 이벤트 발생 시간 (Epoch milliseconds)
correlationId?: string; // 연관된 요청 ID
userId: string; // 이벤트를 트리거한 사용자 ID
dataVersion: string; // 이벤트 데이터 버전 (예: '1.0')
}

2. 시간 변경 이벤트

interface TimeChangedEvent extends BaseTimeMachineEvent {
eventType: 'TIME_CHANGED';
data: {
previousTime: number; // 이전 가상 시간 (Epoch milliseconds)
newTime: number; // 새 가상 시간 (Epoch milliseconds)
reason?: string; // 시간 변경 이유
};
}

3. 사용자 시간 변경 이벤트

interface UserTimeChangedEvent extends BaseTimeMachineEvent {
eventType: 'USER_TIME_CHANGED';
data: {
targetUserId: string; // 가상 시간이 변경된 사용자 ID
previousTime: number; // 이전 가상 시간 (Epoch milliseconds)
newTime: number; // 새 가상 시간 (Epoch milliseconds)
reason?: string; // 시간 변경 이유
};
}

4. 롤백 관련 이벤트

interface RollbackEvent extends BaseTimeMachineEvent {
eventType: 'ROLLBACK_INITIATED' | 'ROLLBACK_COMPLETED' | 'ROLLBACK_FAILED';
data: {
rollbackId: string; // 롤백 작업 ID
targetUserId?: string; // 특정 사용자 롤백인 경우
previousTime: number; // 이전 가상 시간 (Epoch milliseconds)
newTime: number; // 새 가상 시간 (Epoch milliseconds)
affectedDataTypes: string[]; // 영향을 받은 데이터 유형
errorMessage?: string; // 롤백 실패 시 오류 메시지
};
}

이벤트 발행 및 구독

1. 발행 메커니즘

TimeMachine은 GCP Pub/Sub을 사용하여 이벤트를 발행합니다:

  1. 이벤트 발생 시, 이벤트 객체를 생성하고 유효성 검사
  2. 이벤트를 JSON으로 직렬화하여 메시지 페이로드로 사용
  3. 적절한 GCP Pub/Sub 토픽에 메시지 발행
  4. 메시지 발행 상태 모니터링 및 기록
// 예시 - 이벤트 발행기
async publishEvent(event: BaseTimeMachineEvent): Promise<void> {
const topicName = this.getTopicForEvent(event.eventType);
const messageId = await this.pubSubClient
.topic(topicName)
.publish(Buffer.from(JSON.stringify(event)));

await this.eventRepository.recordEvent({
eventId: event.eventId,
eventType: event.eventType,
messageId,
payload: event,
publishedAt: new Date(),
status: 'PUBLISHED',
});
}

2. 구독 메커니즘

다른 서비스가 TimeMachine 이벤트를 처리하는 방법:

  1. 해당 Pub/Sub 토픽에 구독
  2. 수신된 이벤트 메시지 역직렬화
  3. 이벤트 유형 및 데이터 유효성 검사
  4. 적절한 이벤트 핸들러로 라우팅
  5. 이벤트 처리 및 결과 기록
// 예시 - 이벤트 구독자
@PubSubSubscription('time-machine-events')
async handleTimeMachineEvent(
message: PubSubMessage,
ack: () => void,
): Promise<void> {
try {
const event = JSON.parse(message.data.toString()) as BaseTimeMachineEvent;

// 이벤트 유형에 따른 핸들러 호출
switch (event.eventType) {
case 'TIME_CHANGED':
await this.handleTimeChanged(event as TimeChangedEvent);
break;
case 'USER_TIME_CHANGED':
await this.handleUserTimeChanged(event as UserTimeChangedEvent);
break;
// 기타 이벤트 처리
}

// 메시지 확인 처리
ack();
} catch (error) {
// 오류 발생 시 처리 로직
console.error('Event processing error:', error);
// 재시도 가능한 오류인 경우 확인하지 않음
if (this.isRetryableError(error)) {
return;
}
// 복구 불가능한 오류인 경우 메시지 확인 처리
ack();
}
}

이벤트 처리 정책

1. 멱등성

모든 이벤트 핸들러는 멱등성을 보장해야 합니다. 즉, 동일한 이벤트가 여러 번 처리되더라도 결과는 동일해야 합니다:

  • 이벤트 ID를 사용하여 중복 처리 방지
  • 작업 수행 전 상태 확인으로 불필요한 중복 작업 방지
  • 상태 변경은 원자적 연산으로 구현

2. 순서 보장

시간 변경 이벤트는 순서에 영향을 받을 수 있으므로, 처리 순서를 보장해야 합니다:

  • 이벤트 타임스탬프 기반 정렬
  • 동일 사용자에 대한 이벤트는 순차 처리
  • 이전 이벤트 처리 완료 확인 후 다음 이벤트 처리

3. 오류 처리 및 재시도

이벤트 처리 중 발생할 수 있는 오류에 대한 정책:

  • 일시적 오류는 자동 재시도 (지수 백오프 적용)
  • 최대 재시도 횟수 (5회) 초과 시 실패 큐로 이동
  • 복구 불가능한 오류는 즉시 실패 처리 및 알림
  • 모든 실패한 이벤트는 수동 재시도 가능

이벤트 이력 관리

시스템은 모든 이벤트 발행 및 처리 이력을 저장하고 관리합니다:

1. 이벤트 이력 스키마

// Prisma 스키마
model EventHistory {
id String @id @default(uuid())
eventId String @unique // 이벤트 고유 ID
eventType String // 이벤트 유형
messageId String? // GCP Pub/Sub 메시지 ID
payload Json // 이벤트 페이로드 (JSON)
publishedAt DateTime // 발행 시간
status String // 상태: PUBLISHED, DELIVERY_FAILED, PROCESSED
retryCount Int @default(0) // 재시도 횟수
lastRetryAt DateTime? // 마지막 재시도 시간
errorMessage String? // 실패 시 오류 메시지
processingTime Int? // 처리 소요 시간 (밀리초)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

@@index([eventType])
@@index([status])
@@index([publishedAt])
}

2. 이벤트 이력 관리 기능

  1. 이벤트 발행 및 상태 기록
  2. 실패한 이벤트 조회 및 분석
  3. 수동 재시도 기능
  4. 이벤트 처리 성능 모니터링
  5. 이벤트 이력 보관 및 보관 정책 (30일)

실패한 이벤트 처리

1. 실패 감지

이벤트 처리 실패는 다음과 같은 상황에서 발생할 수 있습니다:

  • 발행 서비스와 Pub/Sub 간 연결 문제
  • 구독 서비스의 내부 오류
  • 유효하지 않은 이벤트 데이터
  • 처리 중 시스템 리소스 부족

2. 수동 재시도 프로세스

관리자는 실패한 이벤트를 다음과 같이 재시도할 수 있습니다:

  1. 실패한 이벤트 목록 조회
  2. 재시도할 이벤트 선택
  3. 이벤트 상태 및 데이터 검증
  4. 이벤트 수동 재발행 또는 콜백 처리

API 명세

이벤트 관리 API의 상세 명세는 이벤트 관리 API 문서를 참조하세요.