2016-08-03 59 views
-1

[這個問題是相當模糊的,我爲此道歉。我試圖回答自己的問題]正確腳手架的Node.js應用程序,而不快遞(應用程序不接受請求)

我的建築內,在給定的時間間隔執行各種任務的Node.js應用程序,以解決我的種種煩惱。這裏是全球腳手架(包括青鳥承諾和貓鼬爲DB交互):

var Promise = require("bluebird"); 
 
var mongoose = require('mongoose'); 
 
mongoose.Promise = require('bluebird'); 
 

 
// Personal modules 
 
var bootApp = require(...); 
 
var doStuffA = require(...); 
 
var doStuffB = require(...); 
 
var doStuffC = require(...); 
 

 
// running locally, but meant to be deployed at some point 
 
mongoose.connect('mongodb://localhost:27017/myDatabase'); 
 
var db = mongoose.connection; 
 

 
db.on('error',() => { 
 
    console.log("Error : lost connection !")); 
 
    process.exit(1); 
 
}); 
 

 
db.once('open',() => { 
 
\t 
 
    bootApp() // always start by booting 
 
    .then(() => { // then start the infinite loop of events 
 

 
    setInterval(doStuffA, 1000*60*60); // 1x/1h 
 
    setInterval(doStuffB, 1000*60*10); // 1x/10min 
 
    setInterval(doStuffC, 1000*60*3); // 1x/3min 
 

 
    }).catch((e) => { // errors are handled by doStuffX(), so we should never catch anything here 
 
    console.log(e.message); 
 
    process.exit(1); 
 
    }); 
 
});

每個模塊doStuffX是返回一個承諾,處理自己的錯誤的功能,並且應該在某個時候完成。整個應用

預期的行爲:

  • 的應用程序應該能夠永遠
  • 運行應用程序應儘量doStuffX()在給定的時間間隔,無論是成功還是上次失敗。
  • [可選:該應用程序應在接收到「關閉」信號平滑地關閉而不重試任何doStuff

我的問題:如何建立一個乾淨的支架對於這樣的應用程序?我可以擺脫setInterval並使用承諾嗎?我主要關心的一個問題是,確保之前的doStuffX()實例在開始下一個實例之前完成,即使它涉及以某種方式「殺死」它。

我對任何有關腳手架應用程序的鏈接都開放,但請不要給我一個答覆/涉及EXPRESS的鏈接:我不需要快遞,因爲我的應用程序沒有收到任何請求。 (一切我迄今發現開始與快遞:/)

+1

你爲什麼要擺脫'setInterval()'?您需要一個定時器才能執行循環函數調用。使用承諾無法替代'setInterval()',因爲這兩者是非常不同的動物,所以整個請求聽起來都是錯誤的。 – jfriend00

+1

你的腳手架有什麼問題?它看起來會工作得很好。 – jfriend00

+1

你確定要在任何數據庫錯誤時退出進程嗎?你不應該記錄這些錯誤,也許應該查看錯誤的類型來決定哪些操作是合適的? – jfriend00

回答

1

如果您不想開始下一個doStuffX(),直到前一個完成,則可以用重複的setTimeout()呼叫替換您的setInterval()

function runA() { 
    setTimeout(function() { 
     doStuffA().then(runA).catch(function(err) { 
      // decide what to do differently if doStuffA has an error 
     }); 
    }, 1000*60*60); 
} 

runA(); 

你也可以添加一個超時這個,這樣,如果doStuffA()沒有一定的時間內響應,那麼你採取一些其他措施。這將涉及使用另一個計時器和超時標誌。

+0

我剛剛發現了關於doStuffA()。timeout(10000).then(「whatever」)。當我說doStuffX()處理它的錯誤時,它是真的,但我還沒有找到一種方法來停止進程,如果它正確運行但需要太多時間(我無法解釋它,但可能會發生.. .. )。我覺得我快到了,需要詳細瞭解你讓我意識到什麼 –

+1

@KLôN - '.timeout()'不是ES6標準的承諾功能。它由一些承諾庫支持。如果你的問題實際上包含了你真正想要保護的東西,那麼你會得到更好的答案。要求更好的腳手架根本不會告訴我們你想要什麼。 – jfriend00

+0

你完全正確。事實是:我問了一個非常糟糕的問題,因爲我無法理解我真正想要的東西!儘管你可能會想,你的意見和答案已經幫助了我很多。我接受你的回答,這很有幫助。請您花一些時間閱讀我寫的答案,並告訴我更新的代碼是否看起來不錯? Thx很多爲你的時間和幫助! –

0

[我回答我的問題,想在這裏把所有的東西我後來改變了,萬一有人掉入這個頁面有一天...]

對於支架的貓鼬的一部分,這裏是我走到這一步,一個可靠的長期DB連接:

  • Mongoose documentation給人以奇特的方式,以確保司機絕不會放棄試圖與reconnectTries
  • 重新連接
  • 我真的不明白socketOptionskeepalive似乎與副本有關,所以我現在將它們從我的代碼中刪除
  • 由於Mongoose應該在出現問題時自動重新連接,因此我將保留db.once('open')作爲應用程序代碼本身的訪問權限,即使我不「噸真的聽懂了沒有用db.on('connected')
  • 我建議你閱讀this的差異。

var Promise = require("bluebird"); 
 
var mongoose = require('mongoose'); 
 
mongoose.Promise = require('bluebird'); 
 

 
// Personal modules 
 
var bootApp = require(...); 
 
var doStuffA = require(...); 
 
var doStuffB = require(...); 
 
var doStuffC = require(...); 
 

 
// running locally, but meant to be deployed at some point 
 
var uri = 'mongodb://localhost:27017/myDatabase'; 
 
// the added option makes sure the app will always try to reconnect... 
 
mongoose.connect(uri, { server: { reconnectTries: Number.MAX_VALUE } }); 
 
var db = mongoose.connection; 
 

 
db.on('error',() => { 
 
    console.log("Error with Mongoose connection.")); 
 
}); 
 

 
db.once('open',() => { 
 
\t 
 
    bootApp() // always start by booting 
 
    .then(() => { // then start the infinite loop of events 
 

 
    ////////////////////////////////// 
 
    /// Here goes the actual stuff /// 
 
    ////////////////////////////////// 
 

 
    }).catch((e) => { // errors are handled by doStuffX(), so we should never catch anything here 
 
    console.log(e.message); 
 
    }); 
 
});

現在,對於實際的重複的東西,我的目標是確保一切順利,並沒有進程被卡住。關於我所做的更改:

  • 使用的方法不是本地ES6,但是特定於藍鳥。你可以閱讀關於.timeout().delay(),我發現它非常有用於在乾淨的代碼中鏈接超時和間隔。
  • 在我的腦海裏,.then(runA, runA)應該總是推出runA一個唯一的實例,但我很擔心我是否能最終真正發動兩場並行實例...

// Instead of using setInterval in a bluebird promised environment... 
 

 
setInterval(doStuffA, 1000*60*60); // 1x/1h 
 

 
// I would have liked a full promise chain, but as jfriend00 stated, 
 
// It will end up crashing because the initial promise is never resolved... 
 

 
function runA() { 
 
    return doStuffA() 
 
    .timeout(1000*60*30) // kill the running instance if it takes longer than 30min 
 
    .delay(1000*60*60) // wait 60min 
 
    .then(runA, runA); // whatever the outcome, restart the process 
 
} 
 
runA(); 
 

 
// Therefore, a solution like jfriend00's seems like the way to go : 
 

 
function runA() { 
 
    setTimeout(function() { 
 
     doStuffA() 
 
     .timeout(1000*60*30) 
 
     .then(runA, runA) 
 
    }, 1000*60*60); 
 
} 
 
runA();

+0

這還不是一個有效的答案。除了外部鏈接之外,本身不包含實際內容的答案在這裏無效。 – jfriend00

+0

@ jfriend00:增加更新的代碼和東西。幫助我追蹤思維過程;希望有一天能幫助別人。 –

+1

因爲你無限地鏈接你的承諾,我想知道你是否會遇到內存積累的問題,因爲從第一次調用'runA()'的原始承諾永遠不會得到解決,因爲它不斷地等待鏈接結果。 – jfriend00

相關問題