2012-03-04 3 views
1

RSSフィードを読み、Mongoose経由でMongoDBに内容を保存するバッチプロセスを作成しています。私はスクリプトを実行し、コンテンツをうまく処理します...しかし、スクリプトはコンソールに戻らないでしょう。私の仮説は、私のデータベース接続がまだ開いているということでした。それが私が戻ってこなかった理由です。MongooseとFeedParserでnode.jsでいくつかのコールバックが完了したときのトラッキング

私の解析が完了したばかりのときは追跡できませんでした。なぜなら、まだいくつかのマングース保存操作が行われている可能性があるからです。

オープンなデータベース接続とRSS解析のステータスを追跡する関数を作成しました。しかし、私のコードはひどく冗長に終わった。このようなことをするためのより良いモデル/パターンがあるのだろうかと思います。

var FeedParser = require('feedparser') 
    , mongoose = require('mongoose'); 

var TEST_RSS_URL = "./test/data/20120303-seattle.rss"; 
var OPEN_DB_CONNECTIONS = 0; 
var PARSING_DONE = false; 

/* 
* Keeps track of open database connections, and closes the connection when done 
*/ 
function track_and_close_database(mode) { 
    switch(mode) 
    { 
    case 'open': 
     OPEN_DB_CONNECTIONS++; 
     break; 
    case 'close': 
     OPEN_DB_CONNECTIONS--; 
     if (0 == OPEN_DB_CONNECTIONS && PARSING_DONE) conn.close(); 
     break; 
    case 'parseStart': 
     PARSING_DONE = false; 
     break; 
    case 'parseEnd': 
     PARSING_DONE = true; 
     if (0 == OPEN_DB_CONNECTIONS && PARSING_DONE) conn.close(); 
     break; 
    } 
} 

function parse_stuff(stuff) { 
    // do some stuff 
    setTimeout(console.log("parsed some stuff",20)); 
} 

function main() { 
    parser = new FeedParser(); 

    parser.on('article', function(article) { 
     track_and_close_database('open'); 
     // check to see if we already have this listing 
     stuff_model = conn.model('stuff'); 
     stuff = stuff_model.findOne({'href': article.link}, function (error, doc) { 
      if (error) { 
       track_and_close_database('close'); 
       return; 
      } 
      // this one doesn't exist yet, parse and save 
      if (null == doc) { 
       listing = parse_stuff(article); 

       // if listing is valid, save it! 
       if (null != listing) { 
        listing.save(function (error) { track_and_close_database('close') }); 
       } 
       // parsing failed 
       else track_and_close_database('close'); 
      } 
      // nothing to do, already in the database 
      else track_and_close_database('close'); 
     }); 
    }); 

    // Completed parsing the RSS file 
    parser.on('end', function(article) { 
    track_and_close_database('parseEnd'); 
    }); 

    track_and_close_database('parseStart') 
    parser.parseFile(TEST_RSS_URL); 
} 

// run this thing 
main(); 

答えて

1

私もこの問題に遭遇しました。私は、これを処理するための好ましい方法はイベントであると考えていますが、ソースコードを調べると、何らかのタイプの操作数を保持しているようには見えませんでした。私はそれをEventEmitterに接続しました。 Mongooseが前後の節約のためにイベントを出してしまったので、これをすべてのモデルに組み込む必要はありませんでした。ここで

は、私はそれをやったかのサンプルです:

私のテストの実行が続く
/* lib/render_log.js */ 
/* Model for managing RenderLog */ 

var common = require("./common"); 
common.initialize_locals(global); 

var mongoose = require("mongoose"), 
    Schema = mongoose.Schema; 

var RenderLogSchema = new Schema({ 
    renderer: String, 
    template: String, 
    content: {} 
}); 

RenderLogSchema.pre('save', function(next){ 
    this.db.model('RenderLog').emit('open_db_op', this); 
    next(); 
}); 

RenderLogSchema.post('save', function(){ 
    this.db.model('RenderLog').emit('close_db_op', this); 
}); 

mongoose.connect('mongodb://localhost/time-jr-development'); 

var RenderLog = mongoose.model("RenderLog", RenderLogSchema); 
exports = module.exports = RenderLog; 

/* bin/test_mongoose.js */ 

var async = require('async'); 
var RenderLog = require("../lib/render_log"); 

var ConnectionManager = { 
    open_db_ops: 0, 

    new_db_op: function(){ 
     this.open_db_ops ++; 
    }, 

    close_db_op: function(){ 
    this.open_db_ops --; 
    }, 

    close: function(self){ 
     if(!self) 
     self = this; 
    if(self.open_db_ops > 0){ 
     console.log("Waiting...") 
     process.nextTick(async.apply(self.close, self)); 
    }else{ 
     RenderLog.db.close(); 
    } 
    } 
}; 


RenderLog.on("open_db_op", function(model){ 
    ConnectionManager.new_db_op(); 
}); 

RenderLog.on("close_db_op", function(model){ 
    ConnectionManager.close_db_op(); 
}) 

new RenderLog({renderer: "foo", template: "foo.html", content: {"bar": 1}}).save(); 
new RenderLog({renderer: "foo", template: "foo.html", content: {"bar": 2}}).save(); 
new RenderLog({renderer: "foo", template: "foo.html", content: {"bar": 3}}).save(); 
new RenderLog({renderer: "foo", template: "foo.html", content: {"bar": 4}}).save(); 
new RenderLog({renderer: "foo", template: "foo.html", content: {"bar": 5}}).save(); 
// You have to push this to the next tick otherwise it gets called before the save 
// events have been emitted 
async.nextTick(async.apply(ConnectionManager.close, ConnectionManager)); 
関連する問題