pretty code

2023年12月6日 星期三

離職交接真是門大學問

最近最讓我頭痛的一個交接項目是我剛來這家公司參與的專案,這個專案的目的是要管理 Android based 設備,因為 OTA 等特殊操作緣故,我們的 app 需要 sign key。除了 Client 端,我們 Server 端將 API 與 DB API 切開,故整體又分為兩大 Server。

當初我負責的是 DB 部份,一開始只會寫 C 和把 PHP 當 script 的我,對 Web 架構並沒有那樣熟悉,故使用 C 來寫 Apache 的 plug-in,中間使用 FastCGI protocol 來溝通,這樣的好處是 Web Request 流量可以由 Apache 來承擔,只要頭過身就過?當然我自己本身的處理能力要夠快,這部份的瓶頸一開始只會出現在 DB 端,只要 device 數量不要太誇張,理論上都沒什麼問題。印象當初透過模擬器測試,1000 ~ 2000 台是沒什麼大問題,除了上下載的檔案不能過大否則容易 timeout。

因為最新 Android 版本和當初開發版本已經離很遠了,有些 API 或權限改變不能用那都是可預期的,再加上現在都是用 Android Studio 當開發環境,故這個專案交接其實只要知道 Code 跟文件放在哪裡就好,坦白說這很合理,這個專案應該不會再有重見天日的一天XD

但既然要交接,想說至少讓 Server 端拉最新 Code 下來,配合現在 Node.js 等版本,讓他可以無痛跑起來,避免以後真的要用沒人可以處理,這樣也算是我的小小心意。

沒想到就是這個決定,害我邁向偉大航道的計劃一直無法順利展開,假日除了忙家人的事、土炮結構光比較外,其餘時間都在想怎樣讓 Server 在新的開發環境版本下能夠繼續存活,避免改動更多的 Code。

Web Server

這部份是當初前同事寫的,完全都用 Node.js 開發,但他當初離職交接文件有註明:因為要混淆 code 關係,Node.js 只能用很舊的版本(6.X -> 0.12),而目前最新 LTS 版本是 20.10.0。從這可以看出這中間變化一定不小,為了更貼近現況,我決定使用我目前手上的版本 18.X,這是兩年內的版本,還算可以接受,理論上應該要跳到最新版本,但顧慮到其他人手上版本大概也是介於 18.X 前後,便決定使用這個版本。

前同事很貼心的寫了批次檔可以一鍵安裝,但安裝後一直無法順利執行,原本以為是同事離職文件提到的 npm issue,在多次安裝後依然無法解決。後來靜下心來一看,錯誤雖然是說找不到模組,但確實是有安裝成功,還好在經歷了之前幾個交接項目的荼毒,認定是版本問題,去 N 年前的開發資料夾找到版本號並更新到 package.json,大概改動了幾項,執行便不再有問題。故問題的本質是不要用 * 號當版本號。

其實這會有資安問題,但除非一直用最新版本 daily build 每日做檢查,不然隔一段時間一次進最新版的問題會讓你想哭,由於我沒待過像亞馬遜那樣的大公司,我本身也不是寫 Node.js 的,目前還沒想到怎樣的方式才是最好的?

Device Simulator

搞定 Server 後,雖然已經沒有當初的 Android device 可以跑,但 N 年前我寫了一個可以模擬多台 device 的模擬器,雖然我只實作測試 peformance 需要的指令,但拿來驗證 Server 綽綽有餘!

無奈 socket.io 一直斷線,依稀記得似乎是兩邊的版本要一致?老樣子,找到當初 socket.io 相關模組用版本號,同時更新 Server 及 Simulator package 後,這部份就搞定了。

Record Server

坦白說在搞定上面兩項後,我已經一夜白髮了XD

但路都走到這裡了,還是想完成當初內心承諾,於是再接再勵的勇往直前!原本以為這是最簡單的,畢竟是當初自己開發的,沒想到安裝和設定雖然簡單,但透過 UI 設定 Record Server 的最後步驟一直無法成功?

雖然我都有 Log,但全部架構已經遺忘的差不多了,回頭看文件也是一頭霧水,故一時間也看不出所以然,再加上之前判斷錯誤那一行寫的不嚴謹,多往下做了幾個無謂動作,最後將 Log filter 開到最細並且回過頭來從 request 端看到出問題地方的 code,才讓我發現問題不是出在接收端,而是在我必須發 API 給 Web Server 取 token 那端發生錯誤,由於我使用的是很有名的 libcurl 函式庫,故用我當初最粗 Log filter 的關鍵字就可以 google了,而這個錯誤就是 error code 35。

A problem occurred somewhere in the SSL/TLS handshake. You really want the error buffer and read the message there as it pinpoints the problem slightly more. Could be certificates (file formats, paths, permissions), passwords, and others.

從官方文件可以得知問題是出在 HTTPS 握手階段,只可惜雖然我有將 libcurl debug mode 打開,但並未看到更多錯誤訊息。

我依稀聽過這似乎是 HTTPS 安全性政策更新造成的問題,最初的 SSL 早就被禁用,還好我當初就有留指定 TLS 版本的 code,將註解打開並重新編譯執行檔即可。但不論我指定 1.1 還是 1.2,error code 35 依舊發生?

這不禁讓我懷疑是不是又是 Web Server 某些模組版本需要調整?思考了一下,還是看看之前自己來公司到現在寫的測試資料夾裡面是不是有什麼可以快速發 Web Request 的 code 來利用,我應該至少要有 Node.js、Python、Golang 的資料夾可以搜尋?

剛好第一個找到的就是 Node.js example,用的又是內建模組 https,完全是我需要的,這樣可以先排除版本問題XD

不試不知道,Web Server 居然有收到 API?但我還是很不敢相信,還好當初這個專案開發完後,有鑒於用 C 開發 Web Service 真是自討苦吃,故當初有稍微自學一下 Golang,並稍微的開發 Golang 版的 Record Server,雖然只實作了 3 個 API,但剛好也是 UI 打過來的 API,拿來驗證也是綽綽有餘,最後發現我的 Golang 版 Server 也是可以順利的發 API 給 Web Server。

事已至此,我也認命了,一定是 libcurl 的問題,雖然我不知道為什麼 TLS 1.2 會有問題就是?

之前用了好幾個第三方 C/C++ 模組,除了一個是 C++ Template 外,每個都要用我慣用的 GCC 重新編譯。

本想直接使用 vcpkg + VC 來搞定,但鑒於之前的使用經驗,我也不會期待可以一次搞定!幸好天公疼憨人,想到去年當 C++ 講師時,為了讓學員最後一堂課作業方便使用,當初網路爬蟲沒有使用 boost 而仍舊使用 libcurl,記得當初所用版本打開 TLS 1.2 是正常的?

最後直接使用官方下載的最新編譯好版本(8.4.0_9)配合我舊版的 TDM-gcc(9.2.0)也是無痛接軌,且此版本似乎不再依賴 openssl?至少我只有 link libcurl.dll.a 加上執行時期的 libcurl.dll 便可以執行 HTTPS request。

終於整體 Server 架構都已搞定,看著訊息打來打去,DB 也如預期的記錄系統使用率歷史資料,今天只要順利跑過一整天測試,我終於可以完成最後一項交接項目了!

後記

一來辦公室就開始壓力測試,昨天下班前無聊順手點了一下 screenshot 指令,device simulator 居然會 crash,雖然多做了錯誤檢查避開這個奇怪錯誤,但想說還是在壓力測試前試著搞定本來可以用的指令?還好昨天洗澡時就覺得這個問題好像跟兩年前幫另一個同事解決 issue 的狀況很像,都是 multiparty form-data empy?

邊喝咖啡邊看之前的 Tech-Note,看來是 Node.js 14 開始,某些平台 stream 會有問題,指定 multiparty = 4.2.2 即可。

今天終於可以輕鬆一下了,只要測試沒有其他大問題,我可以慢慢地為這最後一個交接項目收尾了,一切真是得來不易呀,畢竟也從上星期開始搞到今天XD

放張多台 device screenshot command result 圖留作紀念。


下午還是花了點時間確認一下 openssl 版本,如下圖所示,1.0.1 才算正式支援。我 N 年前使用的 libcurl link 的是 1.0.0o,這也是為什麼不支援 TLS 1.2 的真正原因。


要下班了,留個記錄先,看起來大部份元件有定期回收機制,故會重啟 process,目前只有我的 Record App 和 node.exe 記憶體增加了,但應該尚屬合理,只有大量且多日的壓力測試才能做更進一步的分析。


2023/12/08 更新

前天電腦沒關機讓他又跑了一天,直到昨天 7 點多下班才關掉所有測試,留下最後記錄XD

沒有留言: