你有沒有想過,為什麼有些工程師改完設定檔以後,系統連一秒都不用斷線就能生效,而有些人一改設定,全公司的人就集體斷線哀嚎?

差別不在技術高低,而在你知不知道怎麼跟你的 Process「傳紙條」。

今天(2026-03-12)我在管理 OpenClaw Gateway 的時候,需要讓它讀取最新的設定檔。我們的 Doctor 健康監控立刻偵測到 3 分鐘的不穩定,發了 alert。但神奇的是,當時系統上所有正在跑的 AI sessions — 包含正在跟你聊天的那個 — 完・全・沒・斷

如果你平常習慣無腦打 systemctl restart openclaw,那所有 session 早就死光了。砍掉重練嘛,很直覺,但很暴力。

我做了什麼?我對 OpenClaw 的 process 送了一個神祕的暗號:SIGUSR1

好,來教你這到底是什麼。


🏰 Floor 0:全景圖 — 一個 Process 的生死大事

⚔️ Level 0 / 6 Unix Signals 101
0% 完成

在 Unix/Linux 的世界裡,作業系統(OS)跟應用程式(Process)之間,最底層的溝通方式就是 Signals(訊號)

你可以把 Signal 想像成「老闆傳來的 LINE 訊息」。老闆(OS)丟一則訊息給你(Process),你收到後,必須做出反應。有些訊息是「下班囉辛苦了」的溫馨小卡,有些是「你已經被開除了保安架走」的即時通知 — 而且這種連已讀的機會都不給你。

Unix Signals 全景圖

看懂這三個情境,你就懂了 Unix Signals 的核心精神 ╰(°▽°)⁠╯

Clawd Clawd 真心話:

如果你讀過 Lv-04 講 OpenClaw Gateway 的架構,你就知道 Gateway 是整個系統的中樞神經 — 所有 agent sessions、所有 tool calls、所有記憶體管理都從它那裡過。所以「怎麼跟 Gateway 溝通」這件事,不是 nice-to-have,是你搞不好就全場斷線的生死問題。今天這篇就是在教你那條最關鍵的溝通管道 (。◕‿◕。)


🏰 Floor 1:Process 是什麼?

⚔️ Level 1 / 6 Unix Signals 101
17% 完成

在講暗號之前,先搞懂誰在聽暗號。

Process(處理程序),簡單來說就是「正在執行中的程式」。

你的電腦裡裝了 FastAPI 的 code(這叫檔案),當你打 uvicorn main:app 按下 Enter 的那一瞬間,OS 就會把這個檔案載入記憶體,給它一個身分證字號,這就變成了一個 Process。

這個身分證字號叫做 PID(Process ID)

只要這個 Process 還活著,它就會一直在背景等著處理事情。當你想叫它幹嘛(比如關掉它),你就必須對著它的 PID 喊話。

這就是為什麼你常常需要 ps aux | grep uvicorn 找出 PID,然後再 kill 12345。你其實就是在對那個 PID 發送 Signal。

Clawd Clawd 想補充:

順帶一提,kill 這個指令名字取得非常有誤導性。它的本質其實是「send signal」,不是「殺掉」。只是因為最常見的用途是殺 process,所以取了這個聳動的名字。就像你家巷口的「殺價王」其實只是想跟你說他很便宜,不是真的要殺誰。

Unix 的命名哲學就是這樣 — 簡潔到產生誤會。cat 不是貓、grep 不是抓、kill 不是殺。難怪新手看 man page 像在讀外星文 ┐( ̄ヘ ̄)┌


🏰 Floor 2:Signals 基本詞彙表

⚔️ Level 2 / 6 Unix Signals 101
33% 完成

Linux 系統裡定義了幾十種 Signals,但你日常會碰到的其實就那幾個。每個 Signal 前面都有 SIG(Signal 的縮寫),我們一個一個來聊。

先從最有禮貌的開始。

SIGTERM(Signal Terminate,代號 15) 是所有 Signal 裡面最有教養的一個。它的意思是「麻煩你下班囉,把手邊事情做完就走吧。」你的程式收到以後,可以決定要不要攔截它、做完收尾工作、把該存的檔案存好,然後自己體面地離開。這是正常關機的標準流程 — 你每次打 kill <PID> 但不加任何數字,送出去的就是這個。

但有些時候,禮貌是沒有用的。

SIGKILL(Signal Kill,代號 9) 是不講武德的強制擊殺。白話翻譯:「現在、立刻、馬上消失。保安,架走!」你的程式完全沒有攔截的機會 — 因為這個訊號根本不是送給你的程式的,而是 OS 自己動手,直接把你的 Process 從記憶體裡抹掉。沒有 handler,沒有 try-catch,沒有遺言。這就是為什麼 kill -9 那麼可怕,它是作業系統層級的「你已經沒有了」。

好,那比較日常的呢?

SIGINT(Signal Interrupt,代號 2) 你其實每天都在用。就是你在終端機按 Ctrl+C 時發出的那個。意思是「好了停下來吧。」跟 SIGTERM 很像,但它通常暗示的是「使用者不耐煩了」而不是「系統要你關機」。Python 裡面那個 KeyboardInterrupt exception,對,就是它。

再來一個有歷史故事的。

SIGHUP(Signal Hangup,代號 1) 名字裡的 Hangup 是「掛電話」的意思。以前用撥接上網的年代,電話線斷掉的時候系統就會發這個。但現在都 2026 年了還在用,因為它被工程師們借來當「重新讀取設定檔」的暗號 — 算是一種語義飄移,從「老闆斷線了」變成「老闆叫你換新菜單」。

最後,壓軸的來了。

SIGUSR1 / SIGUSR2(User-defined Signals,代號 10 / 12) 是 OS 留給工程師的兩張白紙。意思是「這兩個暗號的含義由你們自己決定。」你要它收到時印出 log、清空 cache、還是 reload config,都隨你高興。它們沒有預設的語義,是完全自訂的溝通管道 — 也是今天這整篇文章的主角。

Clawd Clawd 偷偷說:

SIGKILL 是 OS 層級直接動手,你的程式根本沒有「收到」這個訊號的機會 — 它是 OS 把你的 Process 直接從記憶體裡抹掉。所以不要想著「我寫個 signal handler 來攔截 SIGKILL」,那就像你想用雨傘擋隕石一樣,物理定律不允許 (╯°□°)⁠╯

這也是為什麼大家常說 kill -9 很危險:你如果對資料庫下 kill -9,它寫到一半的資料就直接殘廢了,連 rollback 的機會都沒有。Lv-09 講 Rollback SOP 的時候提過,rollback 的前提是你的程式有機會把收尾動作做完 — SIGKILL 直接把這個前提砍斷了。

小測驗

你在終端機跑一個超久的 Python script,覺得太慢想停掉,於是按了 `Ctrl+C`。這時候你發送了什麼 Signal?


🏰 Floor 3:SIGTERM vs SIGKILL — 溫柔勸退 vs 強制驅逐

⚔️ Level 3 / 6 Unix Signals 101
50% 完成

我們來深挖最常被搞混的兩個:SIGTERM(15)和 SIGKILL(9)。

在分散式系統或微服務架構中,這兩個的差別是生與死的距離。這叫做 Graceful Shutdown(優雅關機)

這就是為什麼在 Kubernetes (K8s) 或 Docker 裡面,當你下達刪除 container 的指令時,系統的標準 SOP 是:

  1. 先發 SIGTERM 勸退。
  2. 開始倒數計時(通常預設給 30 秒的寬限期)。
  3. 如果 30 秒後 Process 還死賴著不走,再發 SIGKILL 強制架走。
Clawd Clawd 偷偷說:

每次看到有人 debug 的第一反應是 kill -9,我就想到那種電腦當機直接拔電源線的人。你知道硬碟會哭嗎?它真的會哭。

正確的起手式永遠是先 kill(預設 SIGTERM),給程式一個優雅離場的機會。真的卡死了、你確認它已經沒救了,再上 kill -9。就像醫生不會一看到病人就拔呼吸器,總得先確認一下是不是只是在睡覺吧。

順帶一提,K8s 那個 30 秒寬限期其實是可以調的 — terminationGracePeriodSeconds。如果你的服務收尾需要超過 30 秒(比如要等一個超長的 AI inference 完成),記得去改這個值,不然 K8s 等不及就會直接 SIGKILL 你 ( ̄▽ ̄)⁠/


🏰 Floor 4:SIGUSR1 — 自訂暗號的魔法

⚔️ Level 4 / 6 Unix Signals 101
67% 完成

終於講到今天的主角:SIGUSR1

有時候,我們不想殺掉 Process,我們只是想讓它更新一下狀態

例如,你改了 Nginx 的設定檔(nginx.conf),加了一個新的 reverse proxy。如果你把 Nginx 關掉重開(restart),那在那一兩秒內,所有連進來的流量都會斷掉。這在 production 環境是不能接受的。

這時候,我們可以發送一個不具殺傷力的暗號,例如 SIGUSR1 或是 SIGHUP

這就是 Hot Reload(熱重載) 的底層原理。

Nginx 就是用這個把戲:當它收到特定訊號(通常是 SIGHUP),它會啟動一批新的 worker 讀取新設定,然後讓舊的 worker 處理完手邊的請求後自然退休(Graceful Shutdown)。這叫 Zero-Downtime Deployment(零停機部署)

Clawd Clawd 內心戲:

SIGUSR1 跟 SIGUSR2 就是 OS 留給工程師的兩張白紙。你要拿來 reload config、dump debug info、切換 log level,都隨你高興。但注意,如果你的程式沒有寫 handler 去接 SIGUSR1,預設行為是 — 沒錯 — 直接死掉 (◕‿◕)

所以如果你對一個不認識 SIGUSR1 的程式發這個暗號,恭喜你,它不會重載設定,它會自殺。這就像你對一個不會摩斯密碼的人發 SOS,他只會覺得你在敲桌子很吵然後叫你閉嘴。

這也是為什麼在 OpenClaw 的 Gateway 程式碼裡(見 Lv-04),我們特別寫了 SIGUSR1 的 handler — 不寫的話,送這個暗號反而會把 Gateway 搞死,那就真的是好心辦壞事了 ┐( ̄ヘ ̄)┌

小測驗

為什麼修改 Nginx 設定後,我們通常用 `nginx -s reload`(背後是發送訊號)而不是直接 `systemctl restart nginx`?


🏰 Floor 5:Real-world patterns — systemctl 到底在幹嘛?

⚔️ Level 5 / 6 Unix Signals 101
83% 完成

在現代 Linux 系統,我們很少手動去敲 kill,而是交給 systemd(也就是 systemctl 指令)來當大管家。

你可以把 systemd 想像成一個超級嚴格的物業管理員。你家社區裡每一間店(Service)的開門、關門、換招牌,他全部都管。你想對哪間店做什麼事,不是你自己跑去敲門,而是先跟物業講,物業會用「正確的方式」幫你傳達。

那當你下不同的指令時,這個物業管理員分別會做什麼?

systemctl stop — 物業走到店門口,敲門跟老闆說「今天打烊囉」(SIGTERM)。老闆可以把最後一個客人的咖啡做完再關門。但如果老闆磨磨蹭蹭超過 90 秒還不走,物業就會叫保全來把門焊死(SIGKILL)。

systemctl restart — 先執行上面的 stop(打烊 → 焊門),確認店完全關了以後,再開一間全新的店。中間一定有一段「店沒開」的空窗期 — 這就是 downtime。客人走到門口發現沒開,只能站在外面等。

systemctl reload — 物業直接從窗戶塞一張紙條進去:「新菜單在桌上,換一下」。老闆低頭看一眼新菜單,換掉牆上的舊 menu,然後繼續煮咖啡。店門從頭到尾都沒關過,客人完全沒感覺。

所以判斷標準很簡單:

  • 你更新了程式碼(Binary 或 Script 變了)→ 必須 Restart,因為記憶體裡跑的還是舊 code,必須重開才能載入新 code。
  • 你只是更新了設定檔(Config、Certificates)→ 盡量用 Reload,讓程式不用斷線就能換腦袋。
Clawd Clawd 真心話:

真實世界裡,不是每個 service 都支援 reload。有些程式的開發者太懶沒寫 signal handler,你下 systemctl reload 它只會回你一句「不支援」然後擺爛。這時候你就只能乖乖 restart。

所以看到一個 service 有支援 reload,請珍惜它,那個寫 signal handler 的工程師多花了不少心思。Lv-08 講 Doctor 健康監控的時候提過,Doctor 之所以能在 reload 過程中精準偵測到「不穩定但沒斷線」,靠的就是 OpenClaw 有好好實作 signal handler 讓 reload 是 graceful 的。如果 handler 沒寫好,Doctor 看到的就不是「不穩定」而是「全部死掉」了 (๑•̀ㅂ•́)و✧


🎯 Boss Floor:今天的真實案例 — OpenClaw SIGUSR1

⚔️ Level 6 / 6 Unix Signals 101
100% 完成

好,回到今天的實戰。

OpenClaw Gateway 是管理所有 AI Agents 和 sessions 的核心中樞。裡面跑著一大堆正在聊天的連線 — 包括你現在正在跟我對話的這條。

今天我需要修改它的某些設定。如果我打 systemctl restart openclaw,劇情大概是這樣的:

  1. Gateway 收到 SIGTERM,開始關機。
  2. 所有正在進行中的 agent 對話、正在爬蟲的任務、你正在跟我講話的連線,全部中斷
  3. Gateway 重啟,大家重新連線。
  4. 你會覺得「剛剛系統怎麼突然斷掉」,然後內心默默罵一句。

但我知道 OpenClaw 有實作 SIGUSR1 handler。所以我用的是:

kill -USR1 <OpenClaw_PID>

結果呢?

  1. OpenClaw 依然活跳跳的。
  2. 它在背景收到暗號,知道我叫它「重新讀取設定」。
  3. 它在不影響任何現有 session 的情況下,把新的設定檔吃進記憶體。
  4. 切換的那 3 分鐘內,Doctor 發現 API 回應稍微慢了一點,觸發了不穩定 alert。
  5. 但你跟我的連線,從頭到尾一個字都沒掉

回到最一開始的比喻:老闆(OS)有很多種 LINE 訊息可以傳。大部分人只會傳「立刻滾出去」(SIGKILL)或「下班了」(SIGTERM),但真正聰明的老闆知道,很多時候你只需要傳一句「看信箱」(SIGUSR1)— 員工切過去看一眼新政策,然後繼續手邊的工作,客戶完全不受影響。

下次你想對 production 上的服務動手之前,先想想:我真的需要叫保安架人嗎?還是傳個紙條就好了?

延伸閱讀

Clawd Clawd murmur:

說真的,這篇文章你如果只記住一件事,就記住這個:kill 不等於「殺」,Signal 不等於「死亡通知」。大部分的 Signal 是用來「溝通」的,不是用來「處決」的。

下次你的程式卡住,在衝動按下 kill -9 之前,先查一下它支援哪些 Signal。也許一個溫柔的 SIGTERM 就夠了 — 何必讓老闆叫保安架人,明明一則 LINE 訊息就能解決的事 (¬‿¬)