0

私は、データベースからスレッド(Gmailの会話)IDを取り出し、各スレッドIDのすべてのデータをGoogle APIに問い合わせる機能を持っています。スレッドオブジェクトを受信すると、スレッドオブジェクトはデータベースに格納されます。これは、〜1kのメッセージを持つ受信トレイでうまく動作します。しかし、100kを超えるメッセージを持つアカウントではうまくいくかどうかはわかりません。膨大なコールバックがスクリプトを中断するか、十分なRAMが利用可能になるたびに続行しますか?

マシンがメモリ不足になったら、十分なRAMが再び利用可能になるたびにコールバック関数を実行し続けますか?私は(いくつかの点で再実行スクリプト全体を、それが最後に終了した場所から新鮮なRAMを続行?)このパートごとの一部を行うには、このコードを変更する必要があり

function eachThread(auth) { 
    var gmail = google.gmail('v1'); 

    MongoClient.connect(mongoUrl, function(err, db){ 
    assert.equal(null, err); 
    var collection = db.collection('threads'); 
    // Find all data in collection and convert it to array 
    collection.find().toArray(function(err, docs){ 
     assert.equal(null, err); 
     var threadContents = []; 
     // For each doc in array... 
     for (var i = 0; i < docs.length; i++) { 
     gmail 
     .users 
     .threads 
     .get({auth:auth,'userId':'me', 'id':docs[i].id}, function(err, resp){ 
      assert.equal(null, err); 
      threadContents.push(resp); 
      console.log(threadContents.length); 
      console.log(threadContents[threadContents.length - 1].id); 
      var anotherCollection = db.collection('threadContents'); 
      anotherCollection.updateOne(
      {id: threadContents[threadContents.length - 1].id}, 
      threadContents[threadContents.length - 1], 
      {upsert:true}, 
      function(err, result){ 
       assert.equal(null, err); 
       console.log('updated one.'); 
      }); 
      if (threadContents.length === docs.length) { 
      console.log('Length matches!'); 
      db.close(); 
      } 
     });//end(callback(threads.get)) 
     }//end(for(docs.length)) 
    });//end(find.toArray) 
    });//end(callback(mongo.connect)) 
}//end(func(eachThread)) 
+0

RAMであるかどうかわかりませんが、SQL to MongoDBツールで部分的に実装しています。パーツ・バイ・パーツ・バージョンは、異なるサイズのパーツをテストする前に* 2速くなっていました。 – DrakaSAN

+0

@DrakaSAN私はまったく同じでした。私は何百万もの行を持つmySQLデータベースを持っていました。そして、SQLからmongoへの部分的な移行に参加したCRONを作ったのです。しかしそれはPHPでした。私は、このコールバックの世界は、それがどれくらい時間がかかっても、一回の実行としてうまくいくかもしれないと信じています。 – Kunok

+1

あなたができることは 'threadContents'を避けて' resp'自身を挿入することです。ループ内に 'anotherCollection'を作成していて、同じオブジェクトが何度も繰り返されるため意味がありません。それでラムには何の問題もないでしょう。 – sed

答えて

2

あなたはすべてを取得し、配列にプッシュしません場合は、メモリが不足することはありません。また、ループ内のすべての要素で同じオブジェクトをインスタンス化しません。

メモリ不足にならないコードの例ですが、終了時にコールバックを受け取らないということは忘れてはいけません。これを行うには、約束/非同期。 async.mapLimitしてforループを交換

// Fire-and-forget type of function 
// Will not run out of memory, GC will take care of that 
function eachThread(auth, cb) { 
    var gmail = google.gmail('v1'); 

    MongoClient.connect(mongoUrl, (err, db) => { 
    if (err) { 
     return cb(err); 
    } 

    var threadsCollection = db.collection('threads').find(); 
    var contentsCollection = db.collection('threadContents'); 

    threadsCollection.on('data', (doc) => { 
     gmail.users.threads.get({ auth: auth, 'userId': 'me', 'id': doc.id }, (err, res) => { 
     if (err) { 
      return cb(err); 
     } 

     contentsCollection.updateOne({ id: doc.id }, res, { upsert: true }, (err, result) => { 
      if (err) { 
      return cb(err); 
      } 
     }); 
     }); 
    }); 

    threadsCollection.on('end',() => { db.close() }); 
    }); 
} 
+0

パラメータとして 'cb'を追加しました。これは基本的にコールバック変数で、先に定義する必要はありませんか、どこかで定義する必要がありますか? – Kunok

+0

エラー処理のためのcbです。 'eachThread( 'my auth'、(err)=> {if(err){console.error(err)}})'ここに例があります。 – sed

+0

私はこのエラーが発生します: 'TypeError:cbは関数ではありません。 ' – Kunok

1

Now what I am asking, once a machine runs out of memory, will it break or will it continue executing callback functions whenever enough RAM is available again?

を使用すると、メモリが不足した場合は、 OSはプロセスを停止します。 Linuxでは、OOM(Out of Memory)が表示されます。そう、はい、それは壊れるでしょう。

これらのシナリオでは、ストリームまたはジェネレータの使用を検討して、処理する必要があるデータのまとまりをメモリに保持することを検討することがあります。あなたのケースでは

MongoDBが提供するには、このような何かが動作するはずfind方法https://mongodb.github.io/node-mongodb-native/2.0/tutorials/streams/

にストリーム:

var collection = db.collection('threads'); 
var cursor = collection.find() 

cursor.on('data', function(doc) { 
    gmail 
    .users 
    .threads 
    .get({auth:auth,'userId':'me', 'id': doc.id}, function(err, resp) { 
    ... 
    }) 
}) 
1

は、一部の機能で一部を追加することがenoughtです。私はまた、接続を開くことは何千回ではなく、それを開くよりも優れているので、collectionと一緒にanotherCollectionの作成を移動する自由を取った。

またassert.equalcallback(err)に変更しました。 asyncの機能は、すべてを停止する必要があることを理解しており、例外をスローする代わりにきれいに終了することができます。

EDIT:

@chernandoが述べたよう、collection.find().toArrayを使用してRAMにコレクション全体をインポートします。部分的に作業するより良い方法は、データをストリーミングするか、またはDBにチャンクでデータを渡すように依頼することです。

このバージョンでは、collection.find().toArrayを問題なく動作させるのに十分なRAMがあると想定しています。

私は時間があるときに私がコメントで話したツールの適応で、おそらく後で戻ってくるでしょう。

var async = require('async'); 

function eachThread(auth) { 
    var gmail = google.gmail('v1'), 
     limit = 100; //Size of the parts 

    MongoClient.connect(mongoUrl, function(err, db){ 
    assert.equal(null, err); 
    var collection = db.collection('threads'), 
     anotherCollection = db.collection('threadContents'); 
    // Find all data in collection and convert it to array 
    collection.find().toArray(function(err, docs){ 
     assert.equal(null, err); 
     var threadContents = []; 
//Change here 
     async.mapLimit(docs, limit, (doc, callback) => { 
     gmail 
     .users 
     .threads 
     .get({auth:auth,'userId':'me', 'id':docs[i].id}, function(err, resp){ 
      if(err) { 
      return callback(err); 
      } 
      threadContents.push(resp); 
      console.log(threadContents.length); 
      console.log(threadContents[threadContents.length - 1].id); 
      anotherCollection.updateOne(
      {id: threadContents[threadContents.length - 1].id}, 
      threadContents[threadContents.length - 1], 
      {upsert:true}, 
      function(err, result){ 
       if(err) { 
       console.error(err); 
       } else { 
       console.log('updated one.'); 
       } 
       callback(err); 
      }); 
     });//end(callback(threads.get)) 
//Change here 
     }, (error) => { 
     if(error) { 
      console.error('Transfert stopped because of error:' + err); 
     } else { 
      console.log('Transfert successful'); 
     } 
     });//end(async.mapLimit) 
    });//end(find.toArray) 
    });//end(callback(mongo.connect)) 
}//end(func(eachThread)) 
+2

'collection.find()。toArray'はあなたのRAMを熱心に消費することに注意してください。 –

+0

@chernando:本当に良い点 – DrakaSAN

+0

あなたが後で戻ってくるまで、私はこの答えに注目します。 – Kunok

関連する問題