Puppeteer: Отсутствует трассировка стека по тайм-ауту

Созданный на 25 сент. 2017  ·  3Комментарии  ·  Источник: puppeteer/puppeteer

Действия по воспроизведению

  • Версия кукловода: 0.10.1
  • Платформа/версия ОС: 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 есть несколько мест, где кукловод работает асинхронно и где трассировка стека может сбивать с толку.

Решением будет node.js, собирающий асинхронные трассировки стека; все другие решения не будут работать достаточно хорошо в общем случае.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги