一次部署後,正式站起不來。不是某個 API 變慢、不是某個功能報錯——是整個服務開機失敗,健康檢查全紅,所有使用者看到的是服務中斷。
回滾之後查原因,發現凶手是新加的一張表裡的一行 DDL:
CREATE TABLE IF NOT EXISTS metrics (
id BIGINT,
value DOUBLE, -- ← 就是這行
...
);
DOUBLE 在 DuckDB 是合法型別,在 Postgres 不是——Postgres 只認 DOUBLE PRECISION。而我的服務在開機階段會執行 schema 初始化(CREATE TABLE IF NOT EXISTS 那一套),Postgres 一碰到不認識的型別直接拋錯,初始化失敗,服務死在起跑線上。
這條雷的惡性跟 Day 4 是同一個家族:本機完全測不出來。DuckDB 對 DOUBLE 甘之如飴,所有測試綠油油,CI 也過了——因為 CI 環境沒有正式站連線資訊,跑的也是 DuckDB(還記得 Day 2 的 fallback 設計嗎?這個設計的陰暗面就在這裡)。
地雷#1 炸的是單一功能,這條炸的是開機路徑。開機路徑上的錯誤沒有降級空間——不是「某個功能暫時壞掉」,是整個服務不存在。而且 schema 初始化這種程式碼平常根本不會被改到,一旦被改到(加新表、加欄位),又往往夾在一個大功能的部署裡,出事時第一時間不會想到是 DDL。
規則本身簡單到不好意思寫出來:DDL 的浮點型別一律寫 DOUBLE PRECISION,兩邊都認得。 但重點是規則的載體:
CLAUDE.md 地雷清單,並且標注「寫 DOUBLE 會讓正式站開機直接掛」——帶後果的規則才會被認真對待DOUBLE PRECISION——這條規則生效至今,同型事故零复發抽象規則跟具體事故的說服力天差地遠。「注意方言差異」跟「寫 DOUBLE 正式站會開不了機(某年某月某日發生過)」是同一件事的兩種寫法,前者會被忽略,後者不會。地雷清單要寫後者。 無論讀者是人還是 AI,都一樣。