Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions contributions/66075.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
---
pr-url: https://github.com/nodejs/node/pull/66075
---

# worker: remove messageerror listeners on exit

## 문제 내용

Worker 종료 시 등록되어 있던 `messageerror` listener가 정상적으로 제거되지 않는 문제를 수정했다.

관련 코드를 확인한 결과, 실제 Event 이름은 `messageerror`인데 cleanup 과정에서는 `messageerrors`라는 잘못된 이름을 사용하고 있었다.

```text
실제 Event 이름
messageerror

기존 cleanup 코드
messageerrors
```

이 때문에 Worker가 종료돼도 `messageerror` listener가 남아 있을 수 있었다.

관련 Issue: #65782

## 원인 분석

Worker 종료 과정에서는 여러 listener와 resource를 정리한다.

관련 코드는 `lib/internal/worker.js`에 있었고, 기존에는 다음과 같이 작성되어 있었다.

```js
this.removeAllListeners('message');
this.removeAllListeners('messageerrors');
```

하지만 등록되는 실제 Event 이름은 다음과 같다.

```js
worker.on('messageerror', listener);
```

`removeAllListeners()`는 전달된 Event 이름이 정확히 일치해야 하므로 `messageerrors`로는 `messageerror` listener를 제거할 수 없었다.

문제 흐름은 다음과 같았다.

```text
messageerror listener 등록
→ Worker 종료
→ cleanup 실행
→ messageerrors 제거 시도
→ Event 이름 불일치
→ messageerror listener가 남음
```

## 해결 과정

잘못된 Event 이름을 실제 Event 이름으로 수정했다.

```diff
- this.removeAllListeners('messageerrors');
+ this.removeAllListeners('messageerror');
```

코드 변경 자체는 한 줄이었지만, Worker 종료 시 listener가 실제로 정리되는지를 확인하기 위해 회귀 테스트도 함께 추가했다.

## 테스트 및 검증

간단한 Worker를 생성하고 `message`와 `messageerror` Event에 listener를 등록했다.

```js
const worker = new Worker('', { eval: true });
const listener = () => {};

worker.on('message', listener);
worker.on('messageerror', listener);
```

Worker가 종료된 뒤 두 listener가 모두 제거되었는지 확인했다.

```js
worker.on('exit', common.mustCall(() => {
assert.strictEqual(worker.listenerCount('message'), 0);
assert.strictEqual(worker.listenerCount('messageerror'), 0);
}));
```

로컬에서는 다음 테스트와 lint를 실행했다.

```bash
python3 tools/test.py --mode=release parallel/test-worker-messageerror-listener-cleanup
make lint-js
```

두 검증 모두 통과했다.

Codecov에서도 수정된 coverable line들이 테스트에 의해 실행되는 것을 확인했다.

## 리뷰 및 CI

PR을 올린 뒤 일정 시간이 지나 `@nodejs/workers` 팀에 follow-up을 남겼다.

follow-up에서는 다음 내용을 다시 정리했다.

```text
Issue #65782 해결
→ messageerror listener cleanup 수정
→ Regression Test 추가
→ Target Test 통과
→ make lint-js 통과
```

이후 `jasnell`에게 Approved를 받았고, Node.js CI도 여러 차례 실행됐다.

## 결과

PR #66075는 최종적으로 Node.js Core에 Merge되었다.

```text
Status: Merged
Merge commit: d9208ccdccb1c6cd5bd0011df0775e860c5d2d1e
```

## 배운 점

이번 기여를 통해 코드 변경량이 작더라도 실제 API lifecycle에 영향을 줄 수 있다는 점을 배웠다.

특히 EventEmitter에서는 Event 이름이 문자열로 정확히 일치해야 하므로 한 글자 오타도 listener cleanup 실패로 이어질 수 있었다.

또한 작은 수정일수록 단순히 코드만 변경하는 것이 아니라, 같은 문제가 다시 발생하지 않도록 회귀 테스트를 함께 남기는 것이 중요하다는 점을 경험했다.
Loading