Meteor 3.x 환경에서의 meteor-collection-hooks 비동기 훅 활용 및 호환성 가이드

현대 Meteor 애플리케이션은 데이터 계층에 대한 커스텀 로직 확장이 필수적이다. meteor-collection-hooks 패키지는 Mongo.Collection 의 표준 메서드를 가로채는 데 가장 널리 사용되는 도구이며, Meteor 3.x 로의 전환과 함께 네이티브 비동기 처리 지원이 핵심 요구사항으로 부상했다. 본 가이드는 최신 프레임워크 구조에서 비동기 훅을 효과적으로 통합하고 호환성 이슈를 해결하는 방법을 다룬다.

Meteor 3 환경의 비동기 훅 개요

Meteor 3.x 는 프라미스 기반 API 로 완전히 전환되었다. 기존 동기식 콜백은 대부분 deprecated 되었으며, 훅 내부에서 외부 서비스 검증, 캐시 무효화, 이벤트 브로드캐스팅을 수행하려면 async/await 지원이 반드시 필요하다. 업데이트된 라이브러리는 기존 동기식 코드와의 후방 호환성을 유지하면서 동시에 최신 비동기 패턴을 전면 지원한다.

설치 및 아키텍처 구조

프로젝트 루트에서 패키지를 초기화한다:

meteor add matb33:collection-hooks

라이브러리는 내부적으로 각 데이터 조작 유형을 개별 핸들러(insert.js, update.js 등) 로 분리하며, 엄격한 타입 검증을 위한 TypeScript 선언 파일을 포함하고 있다.

핵심 구현 패턴

다음은 변수명 및 로직을 재구성한 5 가지 표준 시나리오이다.

1. 삽입 전 데이터 정제 및 비동기 검증

const UserProfiles = new Mongo.Collection('user_profiles');

UserProfiles.before.insert(async function (currentUser, record) {
  const isValid = await checkExternalAuth(record.externalId);
  if (!isValid) throw new Error('External validation failed');

  record.registrationDate = new Date();
  record.registeredBy = currentUser || 'system';
});

2. 업데이트 시 모디파이어 동적 주입

UserProfiles.before.update(function (currentUser, record, fields, modifier, opts) {
  modifier.$set = modifier.$set || {};
  modifier.$set.lastSynced = new Date();
  // 수정은 반드시 'modifier' 객체에 적용해야 하며, 'record'는 읽기 전용이다.
});

3. 업데이트 후 이벤트 브로드캐스트

UserProfiles.after.update(async function (currentUser, record, fields, modifier, opts) {
  await broadcastStatusChange(record._id, record.status);
});

// 이전 상태 접근:
UserProfiles.after.update({ fetchPrevious: true }, async function (currentUser, record) {
  const changes = this.previous.status !== record.status;
  if (changes) await triggerWebhook(record._id);
});

4. 연쇄 삭제 작업

const Departments = new Mongo.Collection('departments');

Departments.before.remove(function (currentUser, deptRecord) {
  Employees.remove({ departmentId: deptRecord._id });
  EquipmentLogs.remove({ assignedToDept: deptRecord._id });
});

5. 전역 쿼리 필터링 (소프트 삭제)

Articles.before.find(function (currentUser, selector, opts) {
  selector.isArchived = { $ne: true }; // 보관 처리된 문서를 자동으로 필터링
});

Meteor 3.x 호환성 매트릭스

업그레이드 시 훅의 트리거 방식과 실행 구조에서 발생하는 특정 변경 사항을 반드시 점검해야 한다.

훅 카테고리Meteor 2.x 동작Meteor 3.x 동작
쓰기 연산 (insert/update/remove/upsert)동기식 전용비동기/await 지원 + 동기식 폴백
before.find동기식동기식 전용 (비동기 시 예외 발생)
find 커서 트리거동기/비동기 메서드 공용비동기 커서 메서드 전용
findOne 트리거findOnefindOneAsync 전용

핵심 실행 규칙

  • before.find 의 동기 제약: find() 는 동기적으로 커서를 반환해야 하므로, 해당 훅을 async 로 선언하면 런타임 오류가 발생한다. 반드시 동기식으로 작성한다.
  • 비동기 커서 의존성: 쿼리 훅은 이제 fetchAsync(), countAsync(), forEachAsync() 호출 시에만 트리거된다. 기존 동기식 페칭은 훅 레이어를 우회한다.
  • findOne 비동기 마이그레이션: 훅을 활성화하려면 findOne()await findOneAsync() 로 교체해야 한다. 내부 구현은 Tracker.withComputation 을 통해 반응성 컨텍스트를 유지한다.
  • Upsert 실행 흐름: 전용 after.upsert 훅은 존재하지 않는다. 시스템은 항상 before.upsert 를 실행한 후, 영향を受けた 문서 수에 따라 after.insert 또는 after.update 중 하나를 추가로 호출한다.

고급 구성 및 최적화

1. 대량 작업 시 훅 우회

마이그레이션 또는 배치 처리 중 훅 실행을 건너뛰려면 direct 수정자를 사용한다:

Inventory.direct.insertMany(rawData);
Inventory.direct.updateAsync({ sku: 'A1' }, { $inc: { stock: 100 } });

2. 컨텍스트 기반 사용자 데이터 주입

세션 컨텍스트가 없는 서버 측 스크립트 또는 마이크로서비스에서:

import { CollectionHooks } from 'meteor/matb33:collection-hooks';
CollectionHooks.defaultUserId = 'service-account-bot';

3. 동적 훅 라이프사이클 관리

const hookRef = Inventory.before.insert(asyncHookLogic);

// 코드베이스 내 다른 위치에서:
hookRef.remove();
hookRef.replace(differentLogic, { fetchPrevious: false });

실무 가이드라인 및 문제 해결

  1. 동형(Isomorphic) 실행 리스크: 공유 디렉토리에 정의된 훅은 클라이언트와 서버 양쪽에서 실행된다. 중복 트리거를 방지하려면 훅 등록 코드를 server/ 디렉토리로 격리한다.
  2. 연산 취소 로직: before 훅 내에서 false 를 반환하면 데이터베이스 작업이 중단된다. 모든 before 훅은 중단 처리가 적용되기 전까지 순차적으로 모두 실행된다는 점을 유의한다.
  3. 암시적 쿼리 훅: updateremove 는 변경 적용 전 내부적으로 문서를 조회하므로, 의도치 않게 find 또는 findOne 훅을 트리거할 수 있다. 훅 설계 시 멱등성(Idempotency)을 고려한다.
  4. Null 사용자 컨텍스트: 서버에서 직접 시작된 작업은 일반적으로 userIdundefined 를 전달한다. 항상 폴백 로직을 구현하거나 defaultUserId 를 활용한다.
  5. 오류 처리: 비동기 훅 내에서 처리되지 않은 프라미스 거부는 작업을 중단시킨다. 중요한 로직은 try/catch 블록으로 감싸고 구조화된 로깅을 구현하여 트랜잭션 롤백을 방지한다.

Meteor 3.x 로의 전환은 프레임워크 전체의 데이터 처리를 비동기 기준으로 표준화한다. 훅 등록을 *Async 커서 메서드와 일치시키고 네이티브 프라미스 지원을 활용하면, 더 안정적이고 확장 가능한 데이터 계층을 구축할 수 있다. 프로덕션 배포 전 패키지 내 통합 테스트 스위트(Test Suite)를 참조하여 호환성을 검증한다.

태그: meteor JavaScript MongoDB async-hooks reactive-programming

9월 20일 00:11에 게시됨