Node.js 伺服器最初因 systemd EADDRNOTAVAIL 而失敗
我需要在來自外部機器的 http get 請求上啟動一個腳本,為此我正在使用 Node.js。我希望伺服器以系統啟動。一切正常,只是伺服器在啟動過程中啟動得太早了:
-- Logs begin at Mon 2017-01-23 09:55:21 UTC, end at Mon 2017-01-23 10:36:20 UTC. -- Jan 23 09:55:24 powercontrol systemd[1]: Starting Energenie Listener... Jan 23 09:55:24 powercontrol systemd[1]: Started Energenie Listener. Jan 23 09:55:28 powercontrol node[474]: events.js:160 Jan 23 09:55:28 powercontrol node[474]: throw er; // Unhandled 'error' event Jan 23 09:55:28 powercontrol node[474]: ^ Jan 23 09:55:28 powercontrol node[474]: Error: listen EADDRNOTAVAIL 192.168.40.62:8001 Jan 23 09:55:28 powercontrol node[474]: at Object.exports._errnoException (util.js:1022:11) Jan 23 09:55:28 powercontrol node[474]: at exports._exceptionWithHostPort (util.js:1045:20) Jan 23 09:55:28 powercontrol node[474]: at Server._listen2 (net.js:1249:19) Jan 23 09:55:28 powercontrol node[474]: at listen (net.js:1298:10) Jan 23 09:55:28 powercontrol node[474]: at doListening (net.js:1397:7) Jan 23 09:55:28 powercontrol node[474]: at _combinedTickCallback (internal/process/next_tick.js:77:11) Jan 23 09:55:28 powercontrol node[474]: at process._tickCallback (internal/process/next_tick.js:98:9) Jan 23 09:55:28 powercontrol node[474]: at Module.runMain (module.js:607:11) Jan 23 09:55:28 powercontrol node[474]: at run (bootstrap_node.js:420:7) Jan 23 09:55:28 powercontrol node[474]: at startup (bootstrap_node.js:139:9) Jan 23 09:55:28 powercontrol systemd[1]: energenie_listener.service: main process exited, code=exited, s Jan 23 09:55:28 powercontrol systemd[1]: Unit energenie_listener.service entered failed state. Jan 23 09:55:30 powercontrol systemd[1]: energenie_listener.service holdoff time over, scheduling restar Jan 23 09:55:30 powercontrol systemd[1]: Stopping Energenie Listener... Jan 23 09:55:30 powercontrol systemd[1]: Starting Energenie Listener... Jan 23 09:55:30 powercontrol systemd[1]: Started Energenie Listener. Jan 23 09:55:31 powercontrol node[565]: events.js:160 Jan 23 09:55:31 powercontrol node[565]: throw er; // Unhandled 'error' event Jan 23 09:55:31 powercontrol node[565]: ^ Jan 23 09:55:31 powercontrol node[565]: Error: listen EADDRNOTAVAIL 192.168.40.62:8001 Jan 23 09:55:31 powercontrol node[565]: at Object.exports._errnoException (util.js:1022:11) Jan 23 09:55:31 powercontrol node[565]: at exports._exceptionWithHostPort (util.js:1045:20) Jan 23 09:55:31 powercontrol node[565]: at Server._listen2 (net.js:1249:19) Jan 23 09:55:31 powercontrol node[565]: at listen (net.js:1298:10) Jan 23 09:55:31 powercontrol node[565]: at doListening (net.js:1397:7) Jan 23 09:55:31 powercontrol node[565]: at _combinedTickCallback (internal/process/next_tick.js:77:11) Jan 23 09:55:31 powercontrol node[565]: at process._tickCallback (internal/process/next_tick.js:98:9) Jan 23 09:55:31 powercontrol node[565]: at Module.runMain (module.js:607:11) Jan 23 09:55:31 powercontrol node[565]: at run (bootstrap_node.js:420:7) Jan 23 09:55:31 powercontrol node[565]: at startup (bootstrap_node.js:139:9) Jan 23 09:55:31 powercontrol systemd[1]: energenie_listener.service: main process exited, code=exited, s Jan 23 09:55:31 powercontrol systemd[1]: Unit energenie_listener.service entered failed state. Jan 23 09:55:33 powercontrol systemd[1]: energenie_listener.service holdoff time over, scheduling restar Jan 23 09:55:33 powercontrol systemd[1]: Stopping Energenie Listener... Jan 23 09:55:33 powercontrol systemd[1]: Starting Energenie Listener... Jan 23 09:55:33 powercontrol systemd[1]: Started Energenie Listener. Jan 23 09:55:34 powercontrol node[572]: Server running at http://192.168.40.62:8001/
正如你所看到的,在幾次失敗之後,伺服器最終啟動並且之後它工作正常。該
.service
文件如下:[Unit] Description=Energenie Listener After=network.target systemd-journald.service [Service] ExecStart=/usr/bin/node /var/opt/energenie/energenie_listener.js Restart=always RestartSec=2 User=root Group=root Environment=PATH=/usr/bin:/usr/local/bin Environment=NODE_ENV=production WorkingDirectory=/var/opt/energenie [Install] WantedBy=multi-user.target
以及
After=network.target ...
,我試過network-online.target
了,但它沒有任何區別。我應該等待不同的服務嗎?哪一個?
我確實有一個想法:這台機器有一個靜態 IP,但它是通過 DHCP 分配的。如果問題是
network.target
(andnetwork-online.target
) 已啟動,但我試圖在 Node 腳本中聲明的 IP 尚未分配,大概我需要一個服務來等待,這將保證 IP 地址已完全配置。這可能是問題所在嗎?如果是這樣,是否有合適的服務可供依賴?
我將伺服器正在偵聽的 IP 地址從問題日誌中的特定地址更改為萬用字元
0.0.0.0
. 這似乎解決了問題(這表明我對未分配 DHCP 地址的懷疑可能是正確的)。這不是一個完美的解決方案(因為我仍然不知道如何等待 DHCP 分配的地址可用),但由於它對於這種特殊情況沒有任何實際區別,它解決了直接的問題記錄的錯誤。
對於基於套接字的操作,這可能是一個有趣的用途。它不會在啟動時啟動您的服務,而是會在第一次網路請求進入以啟動它時啟動。到時候DHCP網路分配應該就完成了!
在您的服務單元文件中,您向該部分添加條目以
[Service]
聲明 STDIN 的來源:StandardInput=socket
然後創建一個
.socket
與您的文件同名的.service
文件,如下所示:[Unit] Description=Energenie Listener Socket [Socket] # Depending your app, you might also use ListenStream= # or ListenSequentialPacket= See man systemd.socket for details ListenDatagram=192.168.40.62:8001 # Allow binding to addresses that may not be configured yet. FreeBind=true [Install] WantedBy=sockets.target
確保
systemd enable
在重新啟動之前在套接字上執行。有關更多上下文,請參閱
man systemd.socket
或搜尋關於$$ systemd socket activation $$.