土耳其客戶回報
使用優惠碼訂購產品失敗
查看錯誤 Log
看起來是 Sql 參數有錯
有一個欄位沒給值
但是印象中那個 Sql 最近都沒改動
不知道為什麼會壞

因為 Error Log 會記錄當下 request 的參數
拿出來照著再打一次 request
竟然成功了
這下問題嚴重了
無法重現的 Bug 總是特別難修

VPN 到土耳其建立測試帳號
用相同的優惠碼購買產品
也無法重現這個問題

正當我束手無策之際
好險主管下來救援
請客戶提供操作時的 HAR檔案
mysql-tr-0.jpg

然後再把 HAR 檔案轉為 Curl 指令
找到我們的那隻 API
匯入 Postman 再打一次
就可以重現問題了

和 Log 不同的是
HAR 檔案會連 request 的 Header 也記錄下來
於是把 Header 一個一個拿掉後
終於發現是 Accept-Language 帶入 tr-TR 時
API 就會壞掉,跳出 Sql 錯誤
這個值通常是使用者的瀏覽器語系
所以我們才無法重現

重現後問題就解決了一半
在專案裡面搜尋 Accept-Language
發現是在 Request開始時
會把 Culture帶入Accept-Language
類似這樣
mysql-tr-1.jpg

但令人費解的是
只有帶入 tr-TR會壞掉
其他如 ja-JP, zh-TW, es-ES 都正常
因為在本機就可以重現
所以就先把語系鎖定在tr-TR
慢慢 Debug

頭痛醫頭,腳痛醫腳
先修改 insert sql的語法
欄位不要帶參數
直接寫死0
不意外的沒有問題

接著我又突發奇想
把參數換個名字
原本是 presentId
改為 test
竟然也成功了
只是這個成功
帶來的是更深的謎團

冷靜了一下
想說先 commit 一個可以動的版本
結果又有驚奇的發現
在git的比對當中
才發現 Sql 語法是 presentId
但參數是 presentid
mysql-tr-2.jpg
把參數改為presentId
這樣也成功

那就奇怪了
為什麼只有土耳其不分大小寫
其他語系都沒問題
再試了一下test和TEST
竟然也可以過
只有 presentid 和 presentId 不行
大過年的真的是見鬼了
mysql-tr-22.jpg

既然是 nuget 套件拋出的例外
也只能乖乖 trace了
這輩子都還沒使用過 source link
來 debug source code
今日總算是用上了

根據亂馬克的教學
順利的在 MySql 的 sourceCode 下中斷點
在無盡的 F5、F10、F11之後
終於定位到問題點
mysql-tr-3.jpg
mysql-tr-4.jpg

仔細看了一下
MySql 指令初始化的時候
會建立兩個字串的 Dictionary
一個區分大小寫
一個不區分大小寫
mysql-tr-5.jpg

所以部分語系不區分大小寫
這個可以理解
但無法解釋為啥TR時好時壞

這邊看到了一個特殊的字串比對方式
StringComparer.CurrentCultureIgnoreCase
官網的說明如下
有看沒有懂

自己用程式比對了一下
在TR底下
果真 test 和 TEST 一樣
但是 presentid 和 PresentId 不一樣
mysql-tr-6.jpg

這時候我才想到
去看一下土耳其字母到底長怎樣
查到維基百科
真相終於水落石出
mysql-tr-7.jpg

原來土耳其文的 I, i 真的是不同字
而不是大小寫的差異
難怪 test, TEST 會過
只有 id, Id 不會過

俗話說答案就在問題當中
如果我學過土耳其文
可能就不會踩到這個坑了
但也是這次經驗
一次解鎖兩個從未用過的 Debug tool

下回預告
同樣的方法
參數的數量多寡
竟然影響到執行的結果

下一回
排程失靈Bug事件