【问题标题】:Why does this Bottleneck-ed app stall?为什么这个瓶颈的应用程序会停滞不前?
【发布时间】:2016-05-13 18:49:19
【问题描述】:

我有下面的应用程序,但它停止了(下面的代码)。我不知道为什么。我怀疑我可能以错误的方式使用了瓶颈模块。

免责声明:我正在尝试使用这个项目自己学习编程和 NodeJS。请帮忙。

简介

该应用程序的重点是通过请求网页并以 jQuery 样式解析它,从而从数据库中的文档中获取缺失的数据。然后将返回的数据保存到文档中的新键中。该数据库包含约 92 000 个文档。该应用程序使用bottleneckcheeriorequest 模块。我在 OS X 上运行应用程序。

问题

如果我设置了请求数的限制,比如

var limiter = new bottleneck(5, 0);

应用程序在第一批(本例中为 5 个)后停止。但为什么?我怀疑瓶颈可能有问题,以及它期望我的程序如何工作。可能与Bottleneck "Gotchas" 的回调有关?

如果我不设置任何限制,该应用程序就可以正常工作。它获取网页并写入数据库。但是,由于资源超载而导致出现很多错误,因此速度很慢。这就是我告诉瓶颈不要限制的方式:

var limiter = new bottleneck(0, 0);

这些是我得到的错误类型:

{ [Error: getaddrinfo ENOTFOUND www.vestnikverejnychzakazek.cz www.vestnikverejnychzakazek.cz:443]
  code: 'ENOTFOUND',
  errno: 'ENOTFOUND',
  syscall: 'getaddrinfo',
  hostname: 'www.vestnikverejnychzakazek.cz',
  host: 'www.vestnikverejnychzakazek.cz',
  port: 443 }

{ [Error: connect EMFILE 65.52.146.11:443 - Local (undefined:undefined)]
  code: 'EMFILE',
  errno: 'EMFILE',
  syscall: 'connect',
  address: '65.52.146.11',
  port: 443 }


应用代码

'use strict';

var express = require('express');
var router = express.Router();
var assert = require('assert');
var mongo = require('mongoskin');
var path = require('path');
var ObjectID = require('mongodb').ObjectID;
var db = mongo.db("mongodb://localhost:27017/zak", {
    native_parser: true
});
var database = db.collection("zakazky");
var cheerio = require("cheerio");
var request = require("request");
var fs = require("fs");
var toJs = (path.join(__dirname, '../public/javascripts', 'jquery.min.js'));
var jquery = fs.readFileSync(toJs).toString();
var bottleneck = require("bottleneck");
var limiter = new bottleneck(5, 0);



/* GET home page. */
router.get('/', function(req, res) {

var cursor = database.find();

cursor.each(function(err, data) {
    assert.equal(err, null);
    if (data != null) {
        var vvz = "vestnikverejnychzakazek";
        var praha = "zakazky.praha.eu";
        var id = data["_id"];
        var zdroj = data["zdroj"];

        if (zdroj.indexOf(vvz) > -1) {

            if ((data["cpv"] == null) || (data["predpokladana_hodnota"] == null)) {
                limiter.submit(getCPV, id, zdroj, null);
                // getCPV(id, zdroj);

            } else {
                // console.log("we're good");
                return
            }

        } else if (zdroj.indexOf(praha) > -1) {
            // console.log("pha");

        }

    } else {
        // callback();
    }
});



var getCPV = function(id, zdroj, callback) {
    console.log("CPV started");
    var zdroj = zdroj.replace("http://", "https://");
    console.log("zdroj:    " + zdroj);
    var cpv = [];


    var retryWrapper = function(retries) {
        var retries; // I added this
        if (retries === 3) {
            return;
        } else if (retries === undefined) {
            retries = 0;
        } else if (retries > 0) {
            console.log("trying again");
        }


        request(zdroj, function(err, resp, data) {
            if (err) {
                console.log(err);
                return retryWrapper(retries + 1);
            }


            var $ = cheerio.load(data);
            var predpokladnaHodnota = $("[id*='Hodnota1_']").first().attr("value");
            $("[id*='HlavniSlovnik']").each(function() {
                cpv.push(this.attribs.value);

            });


            // let's check what we've got is actual data


            if (cpv.length === 0) {
                return
            } else {
                // send it off
                writeCPV(id, "cpv", cpv)
            }


            if (predpokladnaHodnota == undefined || predpokladnaHodnota == null) {
                return
            } else {
                // send it off
                writeCPV(id, "predpokladana_hodnota", predpokladnaHodnota)
            }


            callback();
        });
    }; // end of retryWrapper

    retryWrapper();
};

var writeCPV = function(id, key, value) {
    id = ObjectID(id);

    (function() {
        console.log("starting DB write 1");
        database.update({
            "_id": id
        }, {
            $set: {
                [key]: value
            }
        }, function(err, results) {
            if (err) {
                console.log("error in Mongo DB: \n------------------------\n" + err);
            }
            console.log("Mongo success!:\n ----------------------\n" + results);
            // callback();
        });
    })();

    };


    // send the browser we're done
    res.sendStatus(200);

});



// ---------------------
module.exports = router;

这是来自数据库的示例文档,包括获取的密钥:

{
    "_id": ObjectId("568d91396912101c1007ab4e"),
    "cena": 1636363,
    "cena_celkem": 1500000,
    "cena_dopocitano": false,
    "created": "2015-04-07T13:45:10.420739",
    "datum_zadani": "2015-02-16",
    "dodavatel": "/api/v1/dodavatel/381836/",
    "druh_rizeni": "/api/v1/druh_rizeni/1116/",
    "id": 1312587,
    "modified": "2015-04-18T14:22:10.765733",
    "nazev": "Pohostinství",
    "pocet_nabidek": 2,
    "podporeno_eu": true,
    "popis": "Kurzy v oblasti pohostinství (formou profesní kvalifikace)",
    "ramcova_smlouva": true,
    "resource_uri": "/api/v1/zakazka/1312587/",
    "skupina": "490648-ISVZUS_2011",
    "typ_zakazky": "/api/v1/typ_zakazky/193/",
    "zadavatel": "/api/v1/zadavatel/131528/",
    "zdroj": "http://www.vestnikverejnychzakazek.cz/en/Form/Display/568547",
    "zdroj_nazev": "isvzus.cz",
    "cpv": ["80000000-4", "80400000-8", "", "", ""],
    "predpokladana_hodnota": "1 500 000,00"
}

请求的示例 URL:

http://www.vestnikverejnychzakazek.cz/en/Form/Display/568547

【问题讨论】:

    标签: node.js mongodb request cheerio


    【解决方案1】:

    这里已经有一段时间了,但万一其他人偶然发现了这个,希望这会对某人有所帮助!

    限制器正在调用 getCPV,它确实在序列结束时调用回调,但是,retryWrapper 中有一些条件语句允许提前返回,因此永远不会调用回调。限制器会堆积起来直到触发,因此请始终确保回调将在所有场景中触发。

    【讨论】:

      猜你喜欢
      • 2013-07-05
      • 1970-01-01
      • 1970-01-01
      • 2011-11-24
      • 2010-11-01
      • 2011-04-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多