Finally...

上了一課!

我寫了一段Code,利用catch SqlException偵測Deadlock, 前兩次延遲一小段時間再試,第三次則直接丟出Exception。在少數特殊情境下,程式要先切換成特定使用者身份,待處理完成後再切回系統身份。程式示意如下:

   1:  try
   2:  {
   3:      for (int i = 0; i < 3; i++)
   4:      {
   5:          try
   6:          {
   7:              if (needImpersonate)
   8:                  changeIdentity(someUser);
   9:              doTheProcess();
  10:              if (needImpersonate)
  11:                  changeIdentity(systemUser);
  12:              break;
  13:          }
  14:          catch (SqlException se)
  15:          {
  16:              //...some code...
  17:              //if deadlock and i<2
  18:              //    log error and 
  19:              //    Thread.Sleep()
  20:              //else
  21:              //    throw DBFailException
  22:          }
  23:      }
  24:  }
  25:  catch (Exception ex)
  26:  {
  27:      LogError(ex);
  28:  }

一直不覺得這寫法有什麼問題,直到昨天被電...

無意間發現一個作業的執行身份不正確,明明系統身份才會執行的作業,卻掛了某個陌生的使用者名稱。滿心狐疑地仔細一查,媽媽咪呀! 從某個時點之後,程式一直在借用這個倒楣的使用者身份處理日常作業,一路下來,有近兩千筆的作業記錄,執行身份都誤植成無辜的受害者...

所幸程式裡涉及身份切換的地方不多,很快的就聚焦到這段程式上。用力想了一下,啊! 如果需要變身的情境,changeIdentity(someUser)過後,doTheProcess()發生非DB錯誤,程式便不會跳進14列catch (SqlException se),而會進入25列的外圈catch中,那麼11列changeIdentity(systemlUser)被略過忘了將身份還原回來,於是系統接著就用someUser一路跑下去。

知道問題根源,解決只在彈指之間。此處只需加上一個finally block,將還原系統身份的Code搬進去。如此不管天崩地裂、海枯石爛,切換回systemUser的程式碼都一定會被執行。(有人可能會懷疑,不是已經break了,還會向下跑嗎? 記住,finally block裡的程式,不管你在try block下了break, continue, return還是Response.End()... 都得乖乖跑完,這點特性要牢記。)

    for (int i = 0; i < 3; i++)
    {
        try
        {
            if (needImpersonate)
                changeIdentity(someUser);
            doTheProcess();
            break;
        }
        catch (SqlException se)
        {
            //...some code...
            //if deadlock and i<2
            //    log error and 
            //    Thread.Sleep()
            //else
            //    throw DBFailException
        }
        finally 
        {
            if (needImpersonate)
                changeIdentity(systemUser);
        }
    }

而我學的教訓是: 永遠要假設每一段程式都可能會出錯,並設想出錯時的因應之道。如果你有某段程式無論如何都要執行,記得善用finally block。

歡迎推文分享:
Published 03 December 2007 12:47 AM 由 Jeffrey
Filed under: ,
Views: 5,681



意見

沒有意見

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 
(提醒: 因快取機制,您的留言幾分鐘後才會顯示在網站,請耐心稍候)

5 + 3 =

搜尋

Go

<December 2007>
SunMonTueWedThuFriSat
2526272829301
2345678
9101112131415
16171819202122
23242526272829
303112345
 
RSS
創用 CC 授權條款
【廣告】
twMVC

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


Syndication