0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Node.jsのストリーム処理における「MaxListenersExceededWarning」の原因と解決方法

Posted at

Node.jsでストリーム処理を行っているときに、以下のような警告が表示されることがあります。

(node:25604) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 finish listeners added to [Transform]. MaxListeners is 10. Use emitter.setMaxListeners() to increase limit

この警告は、ストリームで使用している Transform ストリームが finish イベントのリスナーを10個以上追加したことが原因です。通常、Node.jsの EventEmitterTransform はそのサブクラス)はリスナーが10個以上追加されると警告を出す仕様になっています。この警告が出る理由とその解決方法について説明します。

原因

MaxListenersExceededWarning の警告が出る原因は、Transform ストリームを使い回しているためです。Transform ストリームは、内部でイベント(特に finish イベント)を発火させますが、インスタンスを使い回すことでそのリスナーが複数回追加されてしまいます。これにより、10個以上のリスナーが追加され、警告が発生します。

具体的な例

以下のコードでは、Transform ストリームのインスタンス basicTransform を使い回しています。await pipeline() の中で再利用すると、finish イベントに対するリスナーが積み重なり、警告が発生します。

問題のコード

// データ変換のためのTransformストリームを定義
const basicTransform = new Transform({
    // オブジェクトモードを有効にして、オブジェクトの読み書きを可能にする
    objectMode: true,
    // 各チャンクを変換するための関数
    transform(chunk, _encoding, callback) {
        // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
        const data = evolve(chunk, {
            status: changeApplicationStatus,
            // ...
        });

        callback(null, data);
    },
});

このコードでは basicTransform を一度作成し、それを複数回使い回しています。これが原因で、finish イベントにリスナーが追加されていきます。

解決方法

1. Transform ストリームを毎回インスタンス化する

Transform ストリームのインスタンスを使い回さず、毎回新しいインスタンスを作成することで、リスナーの積み重ねを防ぎます。この方法を採用すると、ストリームごとにリスナーが適切に管理され、警告が発生しません。

修正後のコード

// Transformストリームのインスタンスを毎回作成する関数
const basicTransformFactory = (): Transform => {
    return new Transform({
        // オブジェクトモードを有効にして、オブジェクトの読み書きを可能にする
        objectMode: true,
        // 各チャンクを変換するための関数
        transform(chunk, _encoding, callback) {
            // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
            const data = evolve(chunk, {
                status: changeApplicationStatus,
	              // ...
            });

            callback(null, data);
        },
    });
};

export { basicTransformFactory };

この修正により、basicTransformFactory を呼び出すたびに新しい Transform インスタンスが作成されるので、リスナーの重複がなくなります。

2. removeAllListeners の使用

もし、どうしても同じ Transform ストリームを使い回さなければならない場合は、ストリームを使用した後に removeAllListeners を呼び出して、不要なリスナーを手動で削除することができます。ただし、これはあまり推奨されません。適切なインスタンス管理が重要です。

上手く削除できない場合があります。

basicTransform.removeAllListeners();

最後に

ストリームの使い回しによる MaxListenersExceededWarning の警告を避けるためには、Transform ストリームをインスタンス化する際に毎回新しいものを生成するようにしましょう。この方法により、リスナーの重複を防ぎ、ストリームの挙動を安定させることができます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?