木偶/铬由于缺乏RAM而导致服务器崩溃

hre*_*tic 0 javascript node.js puppeteer

即时通讯使用nodejs / puppeteer将我的用户登录到远程网站...这是它的工作方式

客户端通过socket.io连接到nodejs服务器,客户端发送start_tunnel到nodejs服务器以启动puppeteer和run(socket , data.token );运行该puppeteer的节点调用

    io.on('connection' , function(socket){

        socket.on('start_tunnel' , function (data) {
            fullfillCaptcha[socket.id] = null ;
            set_stat(socket.id , 1 );
            run(socket , data.token );
        })

        socket.on('get_captcha_from_client' , function (data) {

            fullfillCaptcha[socket.id](data);

        })

    });

    var fullfillCaptcha = {};
    var pay_stats = {} ;

    function captchaPromise(id){
        return  new Promise(resolve => fullfillCaptcha[id] = resolve);
    }
Run Code Online (Sandbox Code Playgroud)

这是给run木偶吃午餐的功能...。我已经注释了代码,因此其易于阅读...基本上,它打开了一个包含带有验证码的表单的网页,从验证码图像中获取屏幕截图,并将其发送给客户端,接收从客户端输入验证码,将其放入输入中并提交表单

async function run(socket , token ) {

   /// OPENING THE WEB PAGE 
    const browser = await puppeteer.launch({headless: true , args:['--no-sandbox']});
    const page = await browser.newPage();
    await page.goto('http://example.com/init/' + token );

    await Promise.race([
        page.waitForNavigation(),
        page.waitForSelector(".Error")
    ]);

   /// CHECKING FOR ERROR

    if (await page.$(".Error"))
    {
        socket.emit('payment_connection_error' );
        set_stat(socket.id , 4 );
        browser.close();
        return ;
    }



   /// TAKING SCREENSHOT FROM CAPTCHA IMAGE

    console.log( ' current url  ' + page.url() );
    let element =  await page.$('#security');

    await element.screenshot({path: 'public_html/captcha/'+  socket.id+'.png'  });
    set_stat(socket.id , 2 );

    /// SENDING CAPTCHA IMAGE FOR CLIENT 
    socket.emit('send_captcha_to_client' , {text : socket.id+'.png'  });

    /// WAITING FOR CLIENT TO TYPE THE CAPTCHA AND SEND IT BACK TO SERVER 

    var captcha = await captchaPromise(socket.id);

    if( typeof(captcha.W_CAPTCHA) == 'undefined' || captcha.W_CAPTCHA == 'cancel' )
    {
        console.log('canceling ... ');
        set_stat(socket.id , 3 );
        browser.close();
        return ;
    }
    console.log( ' captcha confirm -> ' + captcha.W_CAPTCHA );
    set_stat(socket.id , 3 );

    /// TYPING CAPTCHA IN THE INPUT AND SUBMITTING THE FORM 

    await page.$eval('#CAPTCHA', (el , _captcha) => el.value = _captcha.W_CAPTCHA , captcha );
    await page.click('#doPay');


    /// CHECKING FOR SUCCESS OR ERROR OF FORM AFTER 

    await Promise.race([
        page.waitForNavigation(),
        page.waitForSelector(".Error")
    ]);


    if (await page.$(".Error"))
    {
        const pay_error = await page.$eval('.Error', (element) => {
        return element.innerHTML
    });

        console.log(" error : " + pay_error )
        socket.emit('payment_error' , {text : pay_error });
    }
else
    {

        console.log('all ok') ;
        await page.click('#doSubmitTop');
        await page.waitForSelector('#payment-result');
        console.log( ' current url  ' + page.url() );
        socket.emit('payment_result');



    }

    browser.close();
}
Run Code Online (Sandbox Code Playgroud)

这是问题所在,由于缺少RAM及其使用ram的所有伪程序,我们有很多服务器崩溃……我们有一个不错的vps(4G RAM,2 CPU)……并且当我们在那里进行测试时可以看到服务器负载不大

所以我想知道是不是在这里做错什么,还是有什么地方可以查看日志或什么地方可以看到哪里出了问题?

Mar*_*kát 5

Puppeteer的内存崩溃经常发生。有些页面甚至可能消耗GB的内存,因此很难预测您可以并行运行多少个实例。

如果您运行的是我期望的多个Puppeteer浏览器实例,那么很容易用很少的标签打开内存。

一些使Puppeteer的使用效率更高的内存的方法:

为了确保Puppeteer不会杀死其他进程,您可以使用有限的资源在docker容器中运行它。

我们使用此类https://github.com/apifytech/apify-js/blob/master/src/autoscaled_pool.js根据容器中的可用内存(运行接近100%CPU和100%内存)自动缩放Puppeteer任务尽可能)。