2015-10-23 13 views
6

を実行すると、ETIMEDOUTまたはECONNRESETのエラーが続き、Callback was already calledエラーが続きます。Async.js - ETIMEDOUTとコールバックが既に呼び出されていました

onEachLimitItemコールバックを呼び出す前に、私がreturnを含めていなかったためだと思いました。だから私はasync multiple callbacks documentationごとにそれを含めた。まだそれを解決していない。また、エラーイベントを取り除き、エラーイベントのonEachLimitへのコールバックを削除しようとしましたが、どちらもうまくいきませんでした。私はCallback already called号の周りの他のSOの質問を見ましたが、彼らはストリームに関係していないので、私は解決策を見つけることができませんでした。

私の理解では、ECONNRESETのようなエラーが発生した場合、エラーイベントでコールバックを返し、次のストリームに移りますが、これは当てはまりません。エラーは、それがコネクトを再すなわち自分自身を解決し、再びアズールにエラーが発生した蒸気アップを送信しようとすると、それはほとんどようで、それはそれが「完了」イベントをトリガし、そして我々はCallback already calledを取得し、動作します。

私が正しくストリームイベント中のコールバックを処理していますか?

var Q = require('q'); 
var async = require('async'); 
var webshot = require('webshot'); 
var Readable = require('stream').Readable; 
var azure = require('azure-storage'); 

var blob = azure.createBlobService('123', '112244'); 
var container = 'awesome'; 

var countries = [ 
    'en-us', 'es-us', 'en-au', 'de-at', 'pt-br', 'en-ca', 'fr-ca', 'cs-cz', 'ar-ly', 'es-ve', 
    'da-dk', 'fi-fi', 'de-de', 'hu-hu', 'ko-kr', 'es-xl', 'en-my', 'nl-nl', 'en-nz', 'nb-no', 
    'nn-no', 'pl-pl', 'ro-ro', 'ru-ru', 'ca-es', 'es-es', 'eu-es', 'gl-es', 'en-gb', 'es-ar', 
    'nl-be', 'bg-bg', 'es-cl', 'zh-cn', 'es-co', 'es-cr', 'es-ec', 'et-ee', 'fr-fr', 'el-gr', 
    'zh-hk', 'en-in', 'id-id', 'en-ie', 'he-il', 'it-it', 'ja-jp', 'es-mx', 'es-pe', 'en-ph' 
]; 

var uploadStreamToStorage = function (fileName, stream, onEachLimitItem) { 
    var readable = new Readable().wrap(stream); 
    var writeable = blob.createWriteStreamToBlockBlob(container, fileName); 

    readable.pipe(writeable); 

    writeable.on('error', function (error) { 
     return onEachLimitItem.call(error); 
    }); 

    writeable.on('finish', function() { 
     onEachLimitItem.call(null); 
    }); 
}; 

var takeIndividualScreenshot = function (ID, country, onEachLimitItem) { 
    var fileName = ID + '-' + country + '.jpg'; 
    var url = 'https://example.com/' + country + '/' + ID; 

    webshot(url, function (error, stream) { 
     if (error) { throw 'Screenshot not taken'; } 

     uploadStreamToStorage(fileName, stream, onEachLimitItem); 

    }); 
}; 

var getAllCountriesOfId = function (ID) { 
    var deferred = Q.defer(); 
    var limit = 5; 

    function onEachCountry(country, onEachLimitItem) { 
     takeIndividualScreenshot(ID, country, onEachLimitItem); 
    } 

    async.eachLimit(countries, limit, onEachCountry, function (error) { 
     if (error) { deferred.reject(error); } 
     deferred.resolve(); 
    }); 

    return deferred.promise; 
}; 

var createContainer = function() { 
    var df = Q.defer(); 
    var self = this; 

    blob.createContainerIfNotExists(this.container, this.containerOptions, function (error) { 

     if (error) { df.reject(error); } 

     df.resolve(self.container); 
    }); 

    return df.promise; 
}; 

createContainer() 
    .then(function() { 
     return getAllCountriesOfId('211007'); 
    }) 
    .then(function() { 
     return getAllCountriesOfId('123456'); 
    }) 
    .fail(function (error) { 
     log.info(error); 
    }); 

enter image description here

+0

ことの一つは、私は(RAMの8ギガバイト)ローカル対私のVM(RAMの3ギガバイト)でこれを実行すると、スクリプトがとき 'ECONNRESET'エラーをスローし続けていることであるということであるIそれを私のVM上で実行してください。 – Blexy

答えて

4

あなたが既に知っているとしてあなたは、あなたのコールバックが二回呼び出させています。質問は;ストリームの反復処理中にすべてのエラーを停止したいのですか、ストリームからすべてのエラーを累積したいのですか?

あり、あなたがすでにやっているエラーをキャッチして処理する複数の方法がありますが、あなたは致命的なエラーにあなたのデータストリームからの追加の呼び出しにつながるエラーオブジェクトを投げされていないため。

あなたのコード内の実際の問題は、あなたのリターンの範囲によるものです。エラーを処理してコールバックを返してスクリプトの実行を停止しようとすると、時の戻り値の範囲はストリームエラーハンドラにとってローカルであり、グローバルスクリプトではないため、スクリプトは継続して次の有効なストリームに移動します。

writeable.on('error', function (error) { 
    // This 'return' is in the local scope of 'writable.on('error')' 
    return onEachLimitItem.call(error); 
}); 

おそらく配列を設定し、その関数のローカルスコープの外でエラーを処理する可能性があります。すなわち

// Set the array's scope as global to the writable.on() error 
var errResults = []; 
writeable.on('error', function (error) { 
    // Push the local scoped 'error' into the global scoped 'errResults' array 
    errResults.push(error); 
}); 

writeable.on('finish', function() { 
    // Are there any errors? 
    return (errResults.length > 0) ? 
    onEachLimitItem.call(errors) : onEachLimitItem.call(null); 
}); 

これは、問題に取り組むことができる単なる方法です。

Joyent(元のnode.js言語バッカー)から提供されているエラー処理ヘルプを読んだことがあるかどうかはわかりませんが、エラーを処理する際のオプションについてはよく分かります。私は気づい

https://www.joyent.com/developers/node/design/errors

+0

こんにちはjas- @、私は 'Q'の.failエラーリスナーを使用していますが、ちょうど(私は上記のスクリプトにあることを追加しました)私が使用しているロガーにエラーを送信します。ストリームからすべてのエラーを累積したいのですが、スクリプトがクラッシュすることはありません。どうすればよいかわかりません。 Joyentのリンクを今読んでください。 – Blexy

+0

私はQに精通していませんが、あなたのスクリプトはエラーで停止して2回呼び出されるとは言いませんでした。これは、コールバックエラーハンドラを返すスコープが 'writeable.on()'エラー処理関数のローカルなので発生する可能性があります(あなたの場合です)。 –

+0

エラーの処理方法の例を教えてください。ありがとう、これは私のためにすべて新しいです。 – Blexy