KB-ScriptTimeout! Then?
0 |
"當ScriptTimeout發生時,ASPX會繼續執行? 還是嘎然而止?"
以上問題的答案將牽動IIS的調校哲學,當系統發生問題時而導致大量Request處理逾時,調整ScriptTimeout的長短,會產生何種效應?
在過去的印象中,如果使用者開啟一個要執行很久的ASP/ASPX程式,在程式未執行完成之前,使用者關閉瀏覽器時,ASPX仍會繼續跑完,不受與使用者間連線中斷的影響。我用以下的Code進行驗證...
1: private void writeLog(string msg)
2: {
3: using (System.IO.StreamWriter sw =
4: new System.IO.StreamWriter("d:\\temp\\longrun.log", true))
5: {
6: sw.WriteLine(
7: string.Format("{0:yyyy-MM-dd HH:mm:ss.fff} {1}",
8: DateTime.Now, msg
9: ));
10: }
11:
12: }
13: protected void Page_Load(object sender, EventArgs e)
14: {
15: //Write start log
16: writeLog("Start!");
17: //Wait for 20 seconds
18: System.Threading.Thread.Sleep(20000);
19: //Write end log
20: writeLog("Finished!");
21: }
測試時,開啟IE連上該網頁後立即將IE關閉。20秒後檢查longrun.log,可以看到相隔20秒的兩列Log。於是我們得到證明: 使用者關閉Browser並不妨礙ASPX繼續執行。
2007-06-21 04:20:51.814 Start!
2007-06-21 04:21:11.832 Finished!
那麼,當ScriptTimeout發生時又是如何? 我將web.config <httpRuntime> executionTimeout設為5秒,跑了以下的程式:
1: protected void Page_Load(object sender, EventArgs e)
2: {
3: //Write start log
4: writeLog("Start!");
5: for (int i = 0; i < 30; i++)
6: {
7: System.Threading.Thread.Sleep(1000);
8: //One log per second
9: writeLog("Loop-" + i.ToString());
10: }
11: //Write end log
12: writeLog("Finished!");
13: //Response.Write something
14: Response.Write("Done!");
15: Response.End();
16: }
大約5-15秒左右(依據這串討論中MS Online Support的說法,ScriptTimeout小於1分鐘,會有5-15秒的延遲),網頁傳回以下的錯誤:[HttpException (0x80004005): Request timed out.]
在Log則看到有趣的事,30圈的Loop沒有跑完,在i==5時停住了。
2007-06-21 04:26:50.561 Start!
2007-06-21 04:26:51.561 Loop-0
2007-06-21 04:26:52.561 Loop-1
2007-06-21 04:26:53.561 Loop-2
2007-06-21 04:26:54.561 Loop-3
2007-06-21 04:26:55.561 Loop-4
2007-06-21 04:26:56.561 Loop-5
不過我們還不滿足,希望得到更明確的ScriptTimeout證據。但,程式都中止了,還能再做些什麼事? 之前談過Response.End時產生的ThreadAbortException可以被catch抓到,而我猜ScriptTimeout所引發的中止應該也可以被catch捕捉下來。於是改寫Code如下:
1: protected void Page_Load(object sender, EventArgs e)
2: {
3: //Write start log
4: writeLog("Start!");
5: try
6: {
7: for (int i = 0; i < 30; i++)
8: {
9: System.Threading.Thread.Sleep(1000);
10: writeLog("Loop-" + i.ToString());
11: }
12: }
13: catch (Exception ex)
14: {
15: writeLog("ERROR: " + ex.Message);
16: }
17: //Write end log
18: writeLog("Finished!");
19: //Response.Write something
20: Response.Write("Done!");
21: Response.End();
22: }
Log結果如下:
2007-06-21 04:40:37.580 Start!
2007-06-21 04:40:38.580 Loop-0
2007-06-21 04:40:39.580 Loop-1
2007-06-21 04:40:40.580 Loop-2
2007-06-21 04:40:41.580 Loop-3
2007-06-21 04:40:42.580 Loop-4
2007-06-21 04:40:43.580 Loop-5
2007-06-21 04:40:44.580 Loop-6
2007-06-21 04:40:45.580 Loop-7
2007-06-21 04:40:46.580 Loop-8
2007-06-21 04:40:47.580 Loop-9
2007-06-21 04:40:48.580 Loop-10
2007-06-21 04:40:49.580 Loop-11
2007-06-21 04:40:50.002 ERROR: Thread was being aborted.
抓到了!! cath (Exception ex)抓到了ThreadAbortException。由這項證據可以得知,當程式執行時間超過ScriptTimeout時,W3WP.exe應該是用類似Response.End()的方式強制結束ASPX網頁的執行。
由以上的觀察,我的個人推論是--當程式異常時,設定較短的ScriptTimeout應有助於改善大量Thread被Hang住的狀況,盡早釋放出Resource處理其他仍然健全的功能。但如果程式是卡在Unmanaged World Resource,Thread.Abort並不能讓程式立即由困境中脫身(只能先在Thread上做記號,待控制權交回Managed World時才生效)。另外,以下兩則延伸閱讀中提到Multithread下Thread.Abort可能產生的負面效應,可做為進階設計時的考量。
延伸閱讀:
1.How To Stop a Thread in .NET (and Why Thread.Abort is Evil)
2.Plumbing the Depths of the ThreadAbortException Using Rotor
Comments
Be the first to post a comment