【问题标题】:Puppeteer script on DigitalOcean droplet running 24/7 maxes out memory and crashes运行 24/7 的 DigitalOcean 液滴上的 Puppeteer 脚本最大化内存并崩溃
【发布时间】:2021-01-09 15:34:06
【问题描述】:

我有一个简单的 puppeteer 脚本,我在每月 5 美元的 digitalocean 液滴上运行。脚本如下。该脚本登录到电子商务网站,并不断刷新页面以查找特定交易(如果发现添加到购物车和结帐)。从监控图中可以看出,内存随着每个循环而增加,直到达到最大值,然后脚本崩溃。我认为这里的内存是 RAM,而不是存储空间。

谁能建议一个更好的方法来配置 puppeteer 脚本来解决这个问题?循环运行大约需要 5 秒,运行大约 12 小时,直到内存使用量增加到循环运行时间从每次运行 5 秒爬升到每次运行 30 秒的地步。然后最终内存达到最大值并导致脚本崩溃。

在每次运行中关闭并重新打开浏览器会解决内存问题吗? 是因为我将脚本作为一个永无止境的 .js 文件运行吗?

Droplet 内存截图

const puppeteer = require('puppeteer-extra')
puppeteer.use(require('puppeteer-extra-plugin-stealth')())
const fs = require('fs');
const performance = require('perf_hooks').performance;


(async () => {
  const browser = await puppeteer.launch({
    args: ['--no-sandbox'],
    headless: true
  })
  const page = await browser.newPage()
 
  //Login to page
  await page.goto('https://example.com/login', {waitUntil: 'load', timeout: 0});
  await page.type('[name=email]','xxx@xxx.com');
  await page.click('button[type="submit"]');
  await page.waitForTimeout('input[name=password]');
  await page.type('[name=password]','xxx');
  await page.click('button[type="submit"]');

  var runcount = 0
  var foundcount = 0

  //loops always running after logging in
  while(true){
    var t0 = performance.now();  
    
    await page.goto('https://www.example.com/xxx', {waitUntil: 'load', timeout: 0});
    
    //do some await page.$$eval here
    
  
    runcount++;
    var t1 = performance.now();
    console.log("Run: " + runcount + " | Runtime: " + Math.floor((t1 - t0)/1000);
  
  }
 
  await browser.close()
})()

【问题讨论】:

  • 我会说这是因为您的页面在没有被“发布”的情况下不断增长,我真的不知道 pupeteer 是如何工作的,但我会在 while 循环中创建一个新页面并在最后发布它。无论哪种方式,浏览器都在分配内存,或者页面在分配内存并且永远不会释放它。
  • 我建议不要连续运行脚本,而是使用 Cron 作业每隔十分钟定期运行它。让 PuppeteerJS 浏览器会话运行这么长时间注定会以糟糕的方式结束,因为它会消耗大量内存。而且由于页面没有关闭,因此在此期间任何时候都无法释放内存,这会导致您的 RAM 使用率达到峰值水平。
  • 谢谢,但是对于这个脚本,它需要快速连续运行,所以 10 分钟不是一个选项。
  • 只是为了测试,你可以定期尝试browser.createIncognitoBrowserContext()browserContext.close()——如果罪魁祸首是一些历史/cookies/缓存增长,这可以缓解问题。
  • 另外,您可以尝试page.setRequestInterception() 并阻止任何不需要的资源。尽管您加载的是同一个页面,但它可能会使用来自各种来源的大量广告,这会影响历史/cookies/缓存/会话等。

标签: javascript node.js puppeteer digital-ocean


【解决方案1】:

使用PM2 封装的 Puppeteer 作品 - 是一个有助于观察 node.js 脚本的 javascript 库 - 在引发错误等时重新启动脚本。封装可能对您的情况有所帮助,因为内存阈值的配置当达到指定的限制时重新启动整个脚本,并具有最短的停机时间。 pm2超级好用,只需要全局或本地安装库,然后指明要加载的js文件即可。

图书馆有很好的documentation供你个人使用。

安装后,你需要在你的项目中创建一个生态系统文件.js,像这些,我有2个不同的脚本,但你只能放一个

module.exports = {
  apps : [{
    name: "server-centrodonto",
    script: "./dist/server.js",
    exp_backoff_restart_delay: 100,
    max_memory_restart: '200M',
    watch: false, 
    exec_mode  : "cluster",
    instances: 1,
    env: {
      "NODE_ENV": "development",
      "APP_NAME": "server-centrodonto",
      "PORT": 3030,
      "HOST": "localhost",
      "DATABASE": "centrodonto-database-development"
    },
    env_production : {
      "NODE_ENV": "production",
      "APP_NAME": "server-centrodonto",
      "PORT": 3030,
      "HOST": "localhost",
      "DATABASE": "centrodonto-database"
   }
  },
  {
    name: "wpp-bot-atendente_virtual-centrodonto", 
    // here you put your js file location
    script: "./dist/whatsappBot/AtendenteVirtual_bot.js",
    exp_backoff_restart_delay: 100,
    max_memory_restart: '200M',
    watch: false, 
    exec_mode  : "cluster",
    instances: 1,
    env: {
      "NODE_ENV": "development",
      "APP_NAME": "WPPbot_atendente virtual",
    },
    env_production : {
       "NODE_ENV": "production",
       "APP_NAME": "WPPbot_atendente virtual",
    }
  }
],

};

在你需要像这样配置你的包脚本之后:

 "scripts": {
    "start": "yarn pm2 start ecosystem.config.js --env production",
    "start-dev": "yarn pm2 start ecosystem.config.js"
  },

就我而言,我是在本地安装的。

之后只需运行 yarn start,库就会加载您的脚本。然后您可以使用以下命令查看日志和内存使用情况:pm2 logs 或 pm2 monit

【讨论】:

  • 非常感谢! PM2 正是我所需要的,解决了我所有的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-10
  • 2013-05-19
  • 1970-01-01
  • 2017-03-14
  • 2022-01-13
相关资源
最近更新 更多