開發App的時候候,如果要取得server端的資料,通常就必須透過呼叫API的方式來進行,前陣子在開發時碰到一個critical session的問題,我們遇到的狀況是這樣的:
- 某個App需要取得server端記錄的使用者id、App的功能、最新消息…等資訊,。
- 此App在呼叫API時,會將行動裝置的device unique id傳送到server端,用來辨識不同的對象,並回傳使用者的id。
- Server端接收到device unique id後,會記錄到資料庫中;若是從未出現過的裝置,就要新增一筆紀錄,並將產生的使用者id回傳給App。
從這個需求來看,Server端收到API呼叫時,要作以下的處理:
- 檢查收到的device unique id是否存在於資料庫中 (步驟A)
- 若存在,讀取使用者的id。 (步驟A-1)
- 若不存在,新增一筆使用者資料,並取得新增後的使用者id。 (步驟A-2)
- 將使用者id與查詢的資料打包回傳給App (步驟B)
簡單的程序,對吧?錯了!!!
問題就發生在App啟動的同時,可能一次發出了多筆API呼叫,於是上面這個程序就有可能同時開始進行,實際碰到的情形是這樣的:
- App同時呼叫了2個API(API-1與API-2)
- 2個API同時進行上面的步驟A,查詢device unique id是否存在?
- 結果2個 API取得的結果都是:使用者不存在,進行步驟A-2
- 因為device unique id欄位設定了唯一鍵(unique),因此2個API只有一個成功在資料庫中新增了資料,另一個則失敗
- 結果:
- 一個API正常回傳了使用者的id,和查詢的結果。
- 另一個API因為查不到使用者id,又無法透過新增資料取得新使用者id,而回傳系統層級的錯誤訊息。
最後,App當然就很慘地在某些情況下掛掉了,而且要命的,是Critical session並不是每次都發生,於是,花費了不少額外的時間debug…
如何避免這個問題?首先第一件事當然是在資料表的欄位上,一定要設定唯一鍵(unique),以免建立了不必要的、相同的資料,然後呼叫、檢查的程序,可以改成這樣:
- 以收到的device qnique id直接嘗試在資料庫中新增一筆資料,並檢查新增結果:
- 若成功,表示這個使用者是新使用者,讀取新增後的使用者的id。
- 若新增失敗,表示資料庫中已有此使用者的資料,讀取使用者id。
- 將使用者id與查詢的資料打包回傳給App (步驟B)
搞定~下課!從此App與Server過著幸福快樂的生活…(希望啦~只是他們的生活總是充滿了"驚喜"…身為工程師的你,一定懂的~)