본문 바로가기
개발정리 (nodeJS)

[nodeJS] Node.js에서 이벤트 기반 아키텍처 구현하기

by 할리갈리0 2025. 1. 24.

Node.js는 이벤트 기반 아키텍처를 사용하여 비동기 작업을 처리하는 데 최적화된 환경을 제공합니다.

이벤트 기반 아키텍처는 애플리케이션의 주요 동작을 이벤트로 정의하고, 해당 이벤트가 발생했을 때 적절한 리스너가 동작하도록 설계하는 방식입니다.  이벤트 중심의 설계는 코드의 응집력과 유지 보수성을 높이는 데 큰 도움을 줍니다.

 

1. 이벤트 기반 아키텍처 장점

  • 비동기 처리: 작업을 비동기로 처리하여 효율성과 응답성을 높임.
  • 확장성: 새로운 기능을 추가하기 쉽고, 특정 이벤트 처리 로직을 독립적으로 작성 가능.
  • 유지 보수성: 모듈화된 설계로 코드 가독성과 유지 보수성을 높임.

 

2. EventEmitter 소개

이벤트를 생성하고, 리스너를 등록하거나 제거하며, 이벤트를 발생시키는 기능을 제공하는 클래스

 

EventEmitter 주요 메서드

  • on(event, listener): 특정 이벤트에 리스너를 등록.
  • emit(event, ...args): 이벤트를 발생시키고, 등록된 리스너 실행.
  • once(event, listener): 이벤트에 리스너를 한 번만 등록.
  • off(event, listener) 또는 removeListener(event, listener): 등록된 리스너 제거.

 

3. 프로젝트 구조

project-root/
├── app.js            # 메인 애플리케이션 파일
├── events/           # 이벤트 정의 및 리스너 관리 디렉토리
│   ├── userEvents.js # 사용자 관련 이벤트 정의
│   └── ...           # 추가 이벤트 정의 파일
├── services/         # 비즈니스 로직 구현 디렉토리
│   ├── userService.js
│   └── ...
├── database/         # 데이터베이스 연동 관련 파일
│   ├── sqlite.js     # SQLite 초기화 및 연결 설정
│   └── ...
├── utils/            # 유틸리티 코드 디렉토리
│   ├── dbChecker.js  # SQLite 데이터 확인 코드
│   └── ...
├── package.json      # 프로젝트 설정 파일
└── README.md         # 프로젝트 설명 파일

 

4. SQLite 연동

  • 이벤트 기반 아키텍처에서 데이터베이스 연동은 필수적
  • SQLite를 사용하여 데이터를 저장하고 조회하는 기능 구현

SQLite 초기화 및 연결 (database/sqlite.js)

const sqlite3 = require('sqlite3').verbose();

// SQLite 데이터베이스 초기화
const db = new sqlite3.Database('./data.db', (err) => {
  if (err) {
    console.error('Error opening database:', err.message);
  } else {
    console.log('Connected to SQLite database.');
  }
});

// 사용자 테이블 생성
db.serialize(() => {
  db.run(`
    CREATE TABLE IF NOT EXISTS users (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      name TEXT NOT NULL,
      email TEXT UNIQUE NOT NULL
    )
  `);
});

module.exports = db;

 

5. EventEmitter로 이벤트 기반 아키텍처 설계하기

  1. 이벤트 정의: 발생 가능한 이벤트를 정의.
  2. 리스너 등록: 각 이벤트에 대한 리스너를 설정.
  3. 이벤트 발생: 특정 상황에서 이벤트를 발생시키고 데이터를 전달.

events/userEvents.js 파일:

const EventEmitter = require('events');

class UserEmitter extends EventEmitter {}
const userEmitter = new UserEmitter();

module.exports = userEmitter;

 

services/userService.js 파일:

const db = require('../database/sqlite');
const userEmitter = require('../events/userEvents');

// 사용자 등록 서비스
userEmitter.on('userRegistered', (user) => {
  console.log(`Saving user data: ${JSON.stringify(user)}`);
  db.run(
    'INSERT INTO users (name, email) VALUES (?, ?)',
    [user.name, user.email],
    (err) => {
      if (err) {
        console.error('Error saving user:', err.message);
      } else {
        console.log('User data saved successfully.');
      }
    }
  );
});

module.exports = userEmitter;

 

app.js 파일:

const userEmitter = require('./events/userEvents');

// 사용자 등록 이벤트 발생
const newUser = { name: 'Jane Doe', email: 'jane.doe@example.com' };
userEmitter.emit('userRegistered', newUser);

// 데이터베이스 확인 코드
const db = require('./database/sqlite');

db.all('SELECT * FROM users', [], (err, rows) => {
  if (err) {
    console.error('Error fetching users:', err.message);
  } else {
    console.log('Stored users:', rows);
  }
});

 

출력 결과:

Saving user data: {"name":"Jane Doe","email":"jane.doe@example.com"}
User data saved successfully.
Stored users: [ { id: 1, name: 'Jane Doe', email: 'jane.doe@example.com' }

 

6. 고급 기능: 에러 처리 및 이벤트 제거

1) 에러 처리

userEmitter.on('error', (err) => {
  console.error(`Error occurred: ${err.message}`);
});

userEmitter.emit('error', new Error('Something went wrong!'));

 

출력 결과:

Error occurred: Something went wrong!

 

2) 이벤트 제거

const listener = (user) => {
  console.log(`Temporary listener for ${user.name}`);
};

userEmitter.on('userRegistered', listener);
userEmitter.off('userRegistered', listener);
userEmitter.emit('userRegistered', newUser); // 출력 없음

 

 

Node.js에서 이벤트 기반 아키텍처는 비동기 처리를 효율적으로 설계하는 데 필수적인 패턴입니다. EventEmitter를 활용하면 이벤트 흐름을 명확히 정의하고, 유연하고 확장 가능한 애플리케이션을 구현할 수 있습니다.

 

반응형