2016-02-22 7 views
0

У меня есть сервер узлов ZombieJS на Heroku, который отказывается от данных из Интернета. Код сервера вызывается из цикла for на стороне клиента. Каждая итерация цикла делает вызов сервера, который делает царапину зомби. Иногда сервер вылетает с ошибкой ниже. Это происходит только в случае, когда существует несколько итераций цикла for.ZombieJS: прерывисто сбой при вызове многократно из цикла for

Как сделать код достаточно прочным, чтобы обрабатывать несколько одновременных клиентских вызовов, каждый из которых имеет цикл for.

Код:

var express = require('express'); 
var app = express(); 
var Browser = require('zombie'); // tried changing var to const; no difference 
var assert = require('assert'); 

app.set('port', (process.env.PORT || 5000)); 

var printMessage = function() { console.log("Node app running on " + app.get('port')); }; 

var getAbc = function(response, input) 
{ 
    var browser = new Browser(); 
    browser.userAgent = 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0'; 
    browser.runScripts = true; 
    var url = "http://www.google.com/ncr"; 

    browser.visit(url, function() { 
     browser.fill('q', input).pressButton('Google Search', function(){ 
      // parsing number of results from browser object 

      response.writeHead(200, {'Content-Type': 'text/plain'}); 
      response.end(numberOfSearchResults); 
     }); 
    }); 
} 

var handleXyz = function(request, response) 
{ 
    getAbc(response, request.query.input); 
} 

app.listen(app.get('port'), printMessage); 
app.post('/xyz', handleXyz); 

Ошибка:

assert.js:86 
    throw new assert.AssertionError({ 
      ^
No open window with an HTML document 
    at Browser.field (/app/node_modules/zombie/lib/index.js:811:7) 
    at Browser.fill (/app/node_modules/zombie/lib/index.js:903:24) 
    at /app/cfv1.js:42:11 
    at done (/app/node_modules/zombie/lib/eventloop.js:589:9) 
    at timeout (/app/node_modules/zombie/lib/eventloop.js:594:33) 
    at Timer.listOnTimeout (timers.js:119:15) 

У меня есть аналогичный проект с использованием HorsemanJS/PhantomJS, который терпит неудачу подобным образом (я застрял на том, что тоже!): NodeJS server can't handle multiple users

+0

Я провел быстрый тест и, похоже, все в порядке. Можете ли вы добавить browser.debug() и посмотреть, сможете ли вы получить больше информации из своих журналов? –

+0

Вы неоднократно вызывали его из цикла 'for'? Иногда это терпит неудачу. – user3320795

+0

Где бы я положил 'browser.debug()'? – user3320795

ответ

0

Я вижу, что вы создаете новый экземпляр объекта Browser для каждого вызова. Я предполагаю, что предыдущий «Браузер» все еще закрывается или не обрабатывается сборщиком мусора, когда следующий вызов пытается открыть другой. Попробуйте переместить экземпляр браузера вне getAbc()

+0

Я попытался переместить 'var browser = new Browser()' чуть ниже блока 'require', но это не помогло. – user3320795

1

В целом, я думаю, вы должны быть осторожны или просто не генерировать много нежелательных запросов на удаленные серверы. Многие сайты будут дросселировать вас и/или начать отклонять соединения. С учетом сказанного, я считаю, что я нашел источник проблемы в этом конкретном случае.

Я проверил фрагмент кода, и в этом конкретном случае Google сбросит соединение, если вы сделаете слишком много запросов. Когда соединение сбрасывается, одна из переменных заканчивается неудачей утверждения.

Я получаю ошибку, когда соединение сбрасывается:

zombie TypeError: read ECONNRESET 
    at zombie/lib/pipeline.js:89:15 
    at tryCatcher (zombie/node_modules/bluebird/js/release/util.js:16:23) 
    at Promise._settlePromiseFromHandler (zombie/node_modules/bluebird/js/release/promise.js:497:31) 
    at Promise._settlePromise (zombie/node_modules/bluebird/js/release/promise.js:555:18) 
    at Promise._settlePromise0 (zombie/node_modules/bluebird/js/release/promise.js:600:10) 
    at Promise._settlePromises (zombie/node_modules/bluebird/js/release/promise.js:679:18) 
    at Async._drainQueue (zombie/node_modules/bluebird/js/release/async.js:125:16) 
    at Async._drainQueues (zombie/node_modules/bluebird/js/release/async.js:135:10) 
    at Immediate.Async.drainQueues [as _onImmediate] (zombie/node_modules/bluebird/js/release/async.js:16:14) 
    at processImmediate [as _immediateCallback] (timers.js:383:17) 

Я получаю исходную ошибку дальше, но источник проблемы на самом деле из-за выше. Когда выше произойдет, то это приводит к document.documentElement быть значение ложно-у, а затем вызывает это утверждение в зомби/Lib/index.js в функции поля на провал:

assert(this.document && this.document.documentElement, 'No open window with an HTML document'); 

Я думаю, самым простым решением является чтобы обработать ошибку на стороне клиента и попытаться восстановить изящно.

+0

Это замечательно, спасибо большое. Любая рекомендация по устранению ошибки ? – user3320795

+1

Это зависит от UX, который требуется для вашего приложения. Я предполагаю, что вы можете обнаружить, когда ответ является ошибкой.Вы можете либо показать, что произошла ошибка, и попросить пользователя выполнить повторную попытку или повторить попытку. Если вы повторите попытку автоматически, вы, вероятно, захотите что-то вроде экспоненциального отступления, так как сервер по существу перегружен. В идеале вы поймаете ошибку на сервере, чтобы она не разбилась, но я думаю, вам нужно изменить Zombie, чтобы выдать исключение вместо AssertionError (я не знаю, есть ли способ восстановить из отказавшего утверждать). Я полагаю, что это будет больше работы. –