Puppeteer: タイムアウト時にスタックトレースがありません

作成日 2017年09月25日  ·  3コメント  ·  ソース: puppeteer/puppeteer

再現する手順

  • Puppeteerバージョン:0.10.1
  • プラットフォーム/ OSバージョン:OSX

このコードの実行:

'use strict';

const puppeteer = require('puppeteer');

main().then(() => {
  console.log('Done');
});

async function main() {
  process.on('unhandledRejection', r => {
    console.error(r);
    process.exit(1);
  });

  const browser = await puppeteer.launch();

  const page = await browser.newPage();
  await page.goto('https://www.google.com/', {
    waitUntil: 'networkidle'
  });
  await page.waitForSelector('#i-dont-exist', {
    timeout: 500
  });
}

スタックトレースを生成します:

Error: waiting failed: timeout 500ms exceeded
    at Timeout.WaitTask._timeoutTimer.setTimeout (/Users/iftachbar/work/impactlabs/scrapper/node_modules/puppeteer/lib/FrameManager.js:410:58)
    at ontimeout (timers.js:488:11)
    at tryOnTimeout (timers.js:323:5)
    at Timer.listOnTimeout (timers.js:283:5)

これにより、ケースのデバッグが非常に困難になります。
私が期待する直感的な追跡追跡には、 page.waitForSelector()を実行する行が含まれている必要があります。

多分私が考えていない別の解決策があります...

最も参考になるコメント

モンキーパッチで解決しました。 そこにある最善の解決策ではありませんが、大規模なシステムがあり、待機でエラーが発生した場所をデバッグする必要がある場合は必須です。

async function catchTimeoutErrors(callback) {
  const error = new Error('Got timeout');
  try {
    return await callback();
  } catch (e) {
    if (e.stack.indexOf('Timeout.WaitTask._timeoutTimer.setTimeout') >= 0) {
      error.stack += '\nCaused by ' + e.stack;
      throw error;
    }
    throw e;
  }
}

async function patchPuppeteer() {
  const browser = await puppeteer.launch({
    headless: true
  });
  const page = await browser.newPage();
  const mainFrame = page.mainFrame();
  const originalWaitForFunction = mainFrame.__proto__.waitForFunction;
  mainFrame.__proto__.waitForFunction = function waitForFunction() {
    return catchTimeoutErrors(() => originalWaitForFunction.apply(this, arguments));
  };
  await browser.close();
}

バージョン0.10.1用に作成しましたが、0.11.0ではまだテストしていません。

全てのコメント3件

FWIW、タイムアウトコールバックを設定する親関数もスタックトレースから除外されます。

'use strict';

main();

function main() {
  setTimeout(() => { throw new Error('Error in a timeout'); }, 500);
}
Error: Error in a timeout
    at Timeout.setTimeout [as _onTimeout] (test.js:6:28)
    at ontimeout (timers.js:469:11)
    at tryOnTimeout (timers.js:304:5)
    at Timer.listOnTimeout (timers.js:264:5)

モンキーパッチで解決しました。 そこにある最善の解決策ではありませんが、大規模なシステムがあり、待機でエラーが発生した場所をデバッグする必要がある場合は必須です。

async function catchTimeoutErrors(callback) {
  const error = new Error('Got timeout');
  try {
    return await callback();
  } catch (e) {
    if (e.stack.indexOf('Timeout.WaitTask._timeoutTimer.setTimeout') >= 0) {
      error.stack += '\nCaused by ' + e.stack;
      throw error;
    }
    throw e;
  }
}

async function patchPuppeteer() {
  const browser = await puppeteer.launch({
    headless: true
  });
  const page = await browser.newPage();
  const mainFrame = page.mainFrame();
  const originalWaitForFunction = mainFrame.__proto__.waitForFunction;
  mainFrame.__proto__.waitForFunction = function waitForFunction() {
    return catchTimeoutErrors(() => originalWaitForFunction.apply(this, arguments));
  };
  await browser.close();
}

バージョン0.10.1用に作成しましたが、0.11.0ではまだテストしていません。

@barnash puppeteerが非同期であり、スタックトレースが混乱する場所が複数あります。

解決策は、非同期スタックトレースを収集するnode.jsです。 他のすべてのソリューションは、一般的なケースでは十分に機能しません。

このページは役に立ちましたか?
0 / 5 - 0 評価