본문 바로가기
개발/Node.js

winston 사용시 워커 스레드에서 예외 발생시 캐치되지 않는 버그

by hyperhand 2024. 1. 5.

대략의 소스 코드는 아래와 같다.

// index.js
import { Worker } from 'worker_threads';
import logger from './logger.js';

const worker = new Worker('worker.js');

worker.worker.on('message', (value) => {
	logger.info(value);
});

worker.worker.on('error', (err) => {
	logger.error(err);
});

worker.postMessage('message');
// worker.js
import { parentPort } from 'worker_threads';
import logger from './logger.js';

parentPort.on('message', (msg) => {
	logger.log(`received message: ${msg}`);
	throw new Error('Error message!!');
});
// logger.js
import { createLogger, format, transports } from "winston";
import { SPLAT } from 'triple-beam';
const { combine, timestamp, colorize, errors, printf, align } = format;

const formatObject = (param) => {
	if (typeof param === 'object') {
		return JSON.stringify(param);
	}
	return param;
}

const myFormat = {
	transform(info) {
		const splat = info[SPLAT] || [];
		const message = formatObject(info.message);
		const rest = splat.map(formatObject).join(' ');
		info.message = `${message} ${rest}`;
		return info;
	}
}

const logger = createLogger({
	level: 'info',
	format: combine(
		myFormat,
		timestamp({
			format: 'YYYY-MM-DD HH:mm:ss'
		}),
		errors({ stack: true }),
		align(),
		printf(info => `[${info.level}] ${info.timestamp}: ${formatObject(info.message)}`)
	),
	transports: [
		new transports.File({
			filename: 'combined.log',
			maxsize: 1024 * 1024 * 20,
			maxFiles: 20,
		}),
	],
	exceptionHandlers: [
		new transports.File({
	 		filename: 'exceptions.log',
			maxsize: 1024 * 1024 * 20,
            maxFiles: 10,
		}),
	],
	rejectionHandlers: [
		new transports.File({
			filename: 'rejections.log',
			maxsize: 1024 * 1024 * 20,
			maxFiles: 10,
		})
	],
	exitOnError: false,
});

export default logger;

 

간단한 코드로 index.js 에서 워커를 생성해서 메시지를 보내면 워커에서는 메시지를 프린트하고 예외를 발생시켰다. 

로그는 console을 이용하지 않고 winston을 사용했다.

 

그런데 예외를 발생시키면 메인에서 error 메시지 핸들러로 떨어져야 할 것 같은데 그렇지 않고 앱이 먹통이 되는 현상이 발생했다.

 

그래서 워커 사용 방법이 잘못됐나 싶어서 아무리 디버깅을 해봐도 문제가 없어 보였고, 구글링 해봐도 여전히 문제가 뭔지 알수가 없었다.

 

혹시 다른 모듈들과 엮인 문제인가 싶어 하나 하나 살펴보던 중에 winston 설정에서 exceptionHandlers와 rejctionHandlers 속성을 사용한 것이 눈에 들어와 둘 모두 주석 처리한 후 테스트 해보니 다시 정상 작동하기 시작했다. 더 테스트해보니 exceptionHandlers를 설정하면 문제가 되었다. 예외 발생시 winston이 캐치하고 파일로 기록까지 하는 것은 되는데 처리 flow까지 방해할 줄 생각도 못했다. 버그인지 다른 설정 옵션이 있는 건지는 좀 더 살펴봐야겠지만 어차피 combined.log나 rejections.log에도 기록이 되므로 exceptionHandlers 속성 사용 부분은 제거해버렸다.

반응형