Mongoose eachAsync with async function = memory leak?

时间:2017-12-31 05:18:01

标签: node.js mongoose

我不确定这是猫鼬的错误还是我做错了。一旦我使用eachAsync迭代光标时开始使用异步函数,我会遇到内存泄漏(快速上升到4gb然后崩溃)。在尝试了一些事情后,我注意到如果我不使用异步函数作为回调,就不会发生这种情况。

无内存泄漏:

const playerCursor: QueryCursor<IPlayerProfileModel> = PlayerProfile.find({}, projection).lean().cursor();
    await playerCursor.eachAsync(
      (profile: IPlayerProfileModel) => {
        return;
      },
      { parallel: 50 }
    );

内存泄漏:

const playerCursor: QueryCursor<IPlayerProfileModel> = PlayerProfile.find({}, projection).lean().cursor();
    await playerCursor.eachAsync(
      async (profile: IPlayerProfileModel) => {
        return;
      },
      { parallel: 50 }
    );

显然上面的代码没有任何意义,但我需要在函数内执行异步操作。

问题:

导致内存泄漏的原因/我该如何避免?

1 个答案:

答案 0 :(得分:1)

它与async functions的工作方式有关。

引用文档:

  

当异步函数返回一个值时,将解析Promise   返回值。

含义,async函数返回的值将自动换行为Promise

在第一个代码示例中,代码返回undefined,而在第二个代码示例中,代码返回Promise.resolve(undefined)

  

导致内存泄漏的原因是什么?

我没有查看mongoose代码,只有the documentation个州:

  

如果fn返回一个promise,将在迭代到下一个之前等待promise的解析。

由于您的第一个示例没有返回Promise,我认为您的回调是在每个结果上执行的,而不是按顺序执行。

  

我该如何避免呢?

我建议您在第二个代码示例中使用async/wait

在查看代码(自己寻找答案)之后,如果提供了一个不返回promise eachAsync的回调,它将尽可能快地运行回调。

This line是执行回调的地方。下一行检查是否为Promise,如果不是,则立即执行 callback,这会在下一个结果上有效地调用eachAsync回调。如果您的回调具有任何类型的异步操作但立即返回,那么您最终会同时运行成千上万的异步操作。

最重要的是,您将parallel选项设置为100it executes eachAsync callback one hundred times in parallel

这不是mongoose上的错误,因为有些情况需要此行为,并且它确实提供了使用Promise的顺序处理。文档应该提到使用不返回Promise的回调的警告。

再进一步,express uses next on middleware callbacks以便对它们进行排序。