機能追加した途端に、すべてのエンドポイントでMaximum call stack size exceededが連発してきた
直面した問題
消えない。納期が差し迫る中、何も進められなくなってしまった。
{
"status": 500,
"message": "Maximum call stack size exceeded"
}
分からなさすぎて、ChatGPTに聞いてみました。
「Maximum call stack size exceeded」というエラーメッセージは、再帰的な関数(自身を呼び出す関数)が多すぎる回数呼び出され、最終的に呼び出しスタックがオーバーフローする場合に発生するプログラミングのエラーメッセージです。
呼び出しスタックは、プログラムが関数呼び出しを追跡するために使用するデータ構造です。関数が呼び出されると、プログラムは新しいフレームを呼び出しスタックの上部に追加して、関数のローカル変数と実行コンテキストを追跡します。関数が返されると、プログラムは呼び出しスタックからフレームを削除し、関数が呼び出されたポイントから実行を続けます。
再帰的な関数に適切な停止条件がない場合や、再帰の深さが深すぎる場合、呼び出しスタックが大きくなりすぎて、最大サイズを超えると、「Maximum call stack size exceeded」というエラーが発生します。
このエラーを解決するには、再帰の深さを減らすためにコードを最適化したり、再帰を終了する停止条件を追加したりすることができます。一部のプログラミング言語や環境では、最大呼び出しスタックサイズを増やすこともできますが、効率の悪いコードや無限の再帰ループが原因である場合は、実用的な解決策ではないかもしれません。
問題が生じるまでの動き
- 既存機能の並列機能を追加した後に、メソッドを共通化した。
- 共通化は、新たなファイルで行った。
原因
インスタンスを作成したタイミングで実行されるメソッドであるconstructorが、再帰ループしていることでした。例をあげるなら、LeftRepository
とRightRepository
で相互に呼び出し続けていること。
@Service()
export default class LeftRepository {
private rightRepository: RightRepository;
constructor() {
this.rightRepository = Container.get(RightRepository);
}
}
@Service()
export default class RightRepository {
private leftRepository: LeftRepository;
constructor() {
this.leftRepository = Container.get(LeftRepository);
}
}
解決策
独自的な課題及び解決策過ぎるのですが、constructorが競合しないファイルで共通化を行うことでした。
Discussion