IT기술/IT 이론

이벤트 기반 시스템의 핵심 콜 체인(Call Chain) 개념

후스파 2025. 7. 11. 23:08
반응형

시스템 설계에서 중요한 개념인 콜 체인(Call Chain)에 대해 자세히 알아보겠습니다. 특히 이벤트 발행 콜 체인과 이벤트 구독 콜 체인에 초점을 맞추어 이들이 어떻게 작동하는지 설명하겠습니다.


콜 체인이란?

콜 체인은 시스템 내에서 함수나 메서드가 호출되는 순서를 나타내는 개념입니다. 이는 주로 비동기 처리나 이벤트 기반 시스템에서 사용되며, 각 단계에서의 호출 관계를 명확히 합니다.
예를 들어, 웹 애플리케이션에서 사용자가 버튼을 클릭했을 때, 어떤 과정이 발생하는지를 이해하는 데 도움을 줍니다. 콜 체인을 통해 복잡한 시스템의 실행 흐름을 추적하고 디버깅할 수 있으며, 성능 최적화와 오류 처리에도 중요한 역할을 합니다.

콜 체인의 기본 구조

// 기본적인 콜 체인 예시
function handleUserClick() {
    validateInput()
        .then(processData)
        .then(updateUI)
        .then(logActivity)
        .catch(handleError);
}

이벤트 발행 콜 체인

이벤트 발행 콜 체인은 특정 이벤트가 발생했을 때 이를 발행하는 과정에서의 호출 관계를 나타내며, 다음과 같은 단계로 이루어집니다.

1. 이벤트 생성

사용자가 버튼을 클릭하거나 데이터가 업데이트되는 등 특정 조건이 충족되면 이벤트가 생성됩니다. 예를 들어, "사용자가 회원가입을 완료했습니다"라는 이벤트가 생성될 수 있습니다.

// 이벤트 생성 예시
class UserService {
    async registerUser(userData) {
        const user = await this.createUser(userData);

        // 이벤트 생성
        const event = new UserRegisteredEvent({
            userId: user.id,
            email: user.email,
            timestamp: new Date(),
            metadata: { source: 'web', version: '1.0' }
        });

        return { user, event };
    }
}

2. 이벤트 발행

생성된 이벤트는 이벤트 버스를 통해 관련된 구독자에게 발행됩니다. 이벤트 버스는 여러 이벤트를 관리하고, 이를 적절한 구독자에게 전달하는 역할을 합니다.

// 이벤트 버스를 통한 발행
class EventBus {
    constructor() {
        this.subscribers = new Map();
    }

    publish(eventType, eventData) {
        const subscribers = this.subscribers.get(eventType) || [];

        // 모든 구독자에게 이벤트 전달
        subscribers.forEach(subscriber => {
            try {
                subscriber.handle(eventData);
            } catch (error) {
                console.error(`Error handling event ${eventType}:`, error);
            }
        });
    }
}

3. 콜백 호출

이벤트를 수신한 구독자는 자신이 정의한 콜백 함수를 호출하여 해당 이벤트에 대한 처리를 수행합니다. 예를 들어, 회원가입 이벤트가 발생하면 환영 이메일을 발송하는 코드를 실행할 수 있습니다.

// 이벤트 처리 콜백
class EmailService {
    handle(userRegisteredEvent) {
        this.sendWelcomeEmail(userRegisteredEvent.email);
        this.updateMarketingList(userRegisteredEvent.userId);
    }

    async sendWelcomeEmail(email) {
        // 환영 이메일 발송 로직
        await this.emailProvider.send({
            to: email,
            subject: '회원가입을 환영합니다!',
            template: 'welcome'
        });
    }
}

이벤트 구독 콜 체인

이벤트 구독 콜 체인은 이벤트가 발행된 후 이를 구독하는 과정에서의 호출 관계를 나타냅니다. 이 과정은 다음과 같은 단계로 이루어집니다.

1. 이벤트 구독

구독자는 관심 있는 이벤트를 등록합니다. 사용자가 버튼 클릭 이벤트를 구독하면, 버튼 클릭이 발생할 때마다 알림을 받을 수 있습니다.

// 이벤트 구독 등록
class NotificationService {
    constructor(eventBus) {
        this.eventBus = eventBus;
        this.setupSubscriptions();
    }

    setupSubscriptions() {
        // 여러 이벤트 타입 구독
        this.eventBus.subscribe('USER_REGISTERED', this.handleUserRegistered.bind(this));
        this.eventBus.subscribe('ORDER_COMPLETED', this.handleOrderCompleted.bind(this));
        this.eventBus.subscribe('PAYMENT_FAILED', this.handlePaymentFailed.bind(this));
    }
}

2. 이벤트 수신

이벤트가 발행되면 등록된 구독자에게 해당 이벤트가 전달됩니다. 이 과정에서 구독자는 실시간으로 발생하는 이벤트를 파악할 수 있습니다.

// 이벤트 수신 및 라우팅
class EventRouter {
    constructor() {
        this.handlers = new Map();
    }

    route(event) {
        const handler = this.handlers.get(event.type);
        if (handler) {
            // 이벤트 메타데이터 검증
            if (this.validateEvent(event)) {
                handler.process(event);
            }
        }
    }

    validateEvent(event) {
        return event.timestamp && 
               event.type && 
               event.data &&
               (Date.now() - event.timestamp)  e.aggregateId === aggregateId);
    }

    replay(aggregateId) {
        const events = this.getEvents(aggregateId);
        return events.reduce((state, event) => {
            return this.applyEvent(state, event);
        }, {});
    }
}

성능 최적화 전략

이벤트 배치 처리

class BatchEventProcessor {
    constructor(batchSize = 100, flushInterval = 1000) {
        this.batch = [];
        this.batchSize = batchSize;
        this.flushInterval = flushInterval;

        setInterval(() => this.flush(), flushInterval);
    }

    add(event) {
        this.batch.push(event);

        if (this.batch.length >= this.batchSize) {
            this.flush();
        }
    }

    flush() {
        if (this.batch.length > 0) {
            this.processBatch([...this.batch]);
            this.batch = [];
        }
    }

    async processBatch(events) {
        // 배치 단위로 효율적 처리
        await this.bulkInsert(events);
    }
}

이벤트 필터링 및 라우팅

class SmartEventRouter {
    constructor() {
        this.filters = [];
        this.routes = new Map();
    }

    addFilter(predicate) {
        this.filters.push(predicate);
    }

    route(event) {
        // 필터 적용
        const shouldProcess = this.filters.every(filter => filter(event));

        if (shouldProcess) {
            const handlers = this.routes.get(event.type) || [];

            // 우선순위에 따른 처리
            handlers
                .sort((a, b) => a.priority - b.priority)
                .forEach(handler => handler.process(event));
        }
    }
}

마무리

콜 체인은 이벤트 중심 아키텍처에서 이벤트가 발생하고 처리되는 과정을 명확하게 이해하는 데 중요한 역할을 합니다.
이벤트 발행과 구독 과정에서의 호출 체계를 잘 설계하면 시스템의 확장성과 유지 보수성을 높일 수 있습니다. 이를 통해 복잡한 시스템에서도 흐름을 관리하고, 각 구성 요소 간의 상호작용을 원활하게 할 수 있습니다.
특히 마이크로서비스 아키텍처나 분산 시스템에서는 콜 체인의 설계가 더욱 중요해지며, 적절한 패턴과 최적화 전략을 통해 고성능이면서도 안정적인 시스템을 구축할 수 있습니다.

반응형