🙌

機能追加した途端に、すべてのエンドポイントでMaximum call stack size exceededが連発してきた

2023/03/04に公開

直面した問題

消えない。納期が差し迫る中、何も進められなくなってしまった。

{
    "status": 500,
    "message": "Maximum call stack size exceeded"
}

分からなさすぎて、ChatGPTに聞いてみました。

「Maximum call stack size exceeded」というエラーメッセージは、再帰的な関数(自身を呼び出す関数)が多すぎる回数呼び出され、最終的に呼び出しスタックがオーバーフローする場合に発生するプログラミングのエラーメッセージです。

呼び出しスタックは、プログラムが関数呼び出しを追跡するために使用するデータ構造です。関数が呼び出されると、プログラムは新しいフレームを呼び出しスタックの上部に追加して、関数のローカル変数と実行コンテキストを追跡します。関数が返されると、プログラムは呼び出しスタックからフレームを削除し、関数が呼び出されたポイントから実行を続けます。

再帰的な関数に適切な停止条件がない場合や、再帰の深さが深すぎる場合、呼び出しスタックが大きくなりすぎて、最大サイズを超えると、「Maximum call stack size exceeded」というエラーが発生します。

このエラーを解決するには、再帰の深さを減らすためにコードを最適化したり、再帰を終了する停止条件を追加したりすることができます。一部のプログラミング言語や環境では、最大呼び出しスタックサイズを増やすこともできますが、効率の悪いコードや無限の再帰ループが原因である場合は、実用的な解決策ではないかもしれません。

問題が生じるまでの動き

  • 既存機能の並列機能を追加した後に、メソッドを共通化した。
  • 共通化は、新たなファイルで行った。

原因

インスタンスを作成したタイミングで実行されるメソッドであるconstructorが、再帰ループしていることでした。例をあげるなら、LeftRepositoryRightRepositoryで相互に呼び出し続けていること。

@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