檢視原始碼 erlsrv
在 Windows 上將 Erlang 模擬器作為服務執行
描述
此工具程式專用於 Windows NT/2000/XP(以及更新版本的 Windows)。它允許 Erlang 模擬器在 Windows 系統上作為服務執行,讓嵌入式系統無需任何使用者登入即可啟動。以這種方式啟動的模擬器可以透過 Windows 服務小程式進行操作,方式與其他服務類似。
請注意,erlsrv
不是 Windows 的通用服務工具程式,而是專為嵌入式 Erlang 系統設計的。
erlsrv
還提供一個命令列介面,用於註冊、變更、啟動和停止服務。
若要操作服務,登入的使用者必須擁有機器上的管理員權限。Erlang 機器本身(預設)以本機管理員身分執行。這可以使用 Windows 中的「服務」小程式來變更。
與一般服務不同,服務建立的進程可以使用工作管理員「終止」。終止由服務啟動的模擬器會觸發針對該服務指定的「OnFail」動作,該動作可能是重新啟動。
以下參數可以針對每個 Erlang 服務指定
StopAction
- 告知erlsrv
如何停止 Erlang 模擬器。預設值是終止它 (Win32 TerminateProcess),但此動作可以指定任何 Erlang shell 命令,該命令將在模擬器中執行以使其停止。預期模擬器在 shell 中發出命令後 30 秒內停止。如果模擬器沒有停止,它會向服務管理員報告執行中的狀態。OnFail
- 可以是下列其中一項reboot
- 每當模擬器停止時,Windows 系統就會重新啟動(一種更簡單的看門狗形式)。這對於不太重要的系統可能很有用,否則請使用 heart 功能來完成此操作。restart
- 使 Erlang 模擬器在停止時重新啟動(使用該場合註冊的服務參數)。如果模擬器在 10 秒內再次停止,則不會重新啟動,以避免無限迴圈,這可能會使 Windows 系統掛起。restart_always
- 類似於restart
,但不嘗試偵測循環重新啟動;預期會有其他機制來避免這個問題。ignore
(預設) - 每當服務失敗時,會向服務管理員報告服務已停止;必須手動重新啟動。
在使用發行處理的系統上,這始終設定為
ignore
。請改用heart
在失敗時重新啟動服務。Machine
- Erlang 模擬器的位置。預設值是位於與erlsrv.exe
相同目錄中的erl.exe
。如果系統使用發行處理,則這設定為類似於
start_erl.exe
的程式。Env
- 指定模擬器的額外環境。這裡指定的環境變數會新增至服務啟動時通常存在的系統範圍環境區塊。系統範圍環境和服務環境規格中都存在的變數將設定為服務中指定的值。WorkDir
- Erlang 模擬器的工作目錄。必須位於本機磁碟機上(服務啟動時不會掛載網路磁碟機)。服務的預設工作目錄為%SystemDrive%%SystemPath%
。偵錯記錄檔將會放置在此目錄中。Priority
- 模擬器的處理序優先順序。可以是下列其中一項realtime
- 不建議使用,因為機器可能無法讓互動式使用者存取。high
- 如果兩個 Erlang 節點要駐留在一個專用系統上,而且其中一個要優先於另一個,則可以使用。low
- 如果不希望模擬器處理序影響互動式效能,則可以使用。default
- 預設優先順序。
SName 或 Name
- 指定 Erlang 模擬器的簡短或完整節點名稱。Erlang 服務始終是分散式的。預設值是使用服務名稱作為(簡短)節點名稱。DebugType
- 指定 Erlang shell 的輸出要傳送到「偵錯記錄」。記錄檔命名為 <服務名稱>.debug
或 <服務名稱>.debug.
<N>,其中 <N> 是 1 到 99 的整數。記錄檔會放置在服務的工作目錄中(如WorkDir
中所指定)。可以是下列其中一項
new
- 每次叫用服務時都使用個別的記錄檔 (<服務名稱>.debug.
<N>)。reuse
- 重複使用相同的記錄檔 (<服務名稱>.debug
)。console
- 為服務的 Erlang shell 開啟互動式 Windows 主控台視窗。自動停用StopAction
。以互動式主控台視窗啟動的服務無法在登出後繼續執行。OnFail
動作也無法與偵錯主控台搭配使用。none
(預設) - Erlang shell 的輸出會捨棄。
注意
console
選項不是用於生產環境。它只是在開發期間偵錯 Erlang 服務的便利方式。new
和reuse
選項在生產系統中可能看起來很方便,但請考慮到記錄在系統生命週期內會無限增長,且除非重新啟動服務,否則無法截斷。簡而言之,
DebugType
僅用於偵錯。生產期間的記錄最好使用標準的 Erlang 記錄功能來產生。Args
- 將額外引數傳遞至模擬器啟動程式erl.exe
(或start_erl.exe
)。無法在此處指定的引數為-noinput
(StopActions
將無法運作)、-name
和-sname
(它們以任何方式指定)。最常見的用途是指定 Cookie 和要傳遞給init
的旗標 (-s
)。InternalServiceName
- 指定 Windows 內部服務名稱(而不是顯示名稱,即erlsrv
用於識別服務的名稱)。即使重新命名服務,此內部名稱也無法變更,它已固定。
erlsrv
在建立服務時會產生唯一的內部名稱。如果應用程式要使用發行處理,建議保留預設值。如果在 Windows 服務管理員中檢視 Erlang 服務的
內容
,則可以看到內部服務名稱。Comment
- 描述服務的文字註解。並非強制性,但在 Windows 服務管理員中會顯示為服務描述。
在使用發行處理的系統中,服務的命名必須遵循慣例節點名稱_發行版,其中節點名稱是 Erlang 節點名稱的第一部分(直到但不包含「@」),而發行版是應用程式的目前發行版。
erlsrv {set | add} <服務名稱> [<服務選項>]
set
和 add
命令分別修改或新增 Erlang 服務。最簡單的 add
命令形式是沒有任何選項,在此情況下會套用所有預設值(如上所述)。服務名稱是必要的。
每個選項都可以指定而不帶參數,然後會套用預設值。只有在不使用預設值時,才會提供選項的值。例如,erlsrv set myservice -prio -arg
會設定預設優先順序並移除所有引數。
服務選項
-st[opaction] [<erlang shell 命令>]
- 定義StopAction
,即在停止服務時給予 Erlang shell 的命令。預設值為無。-on[fail] [{reboot | restart | restart_always}]
- Erlang 模擬器意外停止時要採取的動作。預設值為忽略。-m[achine] [<erl-command>]
- Erlang 模擬器的完整路徑。絕對不要使用werl
程式來執行此操作。預設值為與erlsrv.exe
相同目錄中的erl.exe
。使用發行處理時,這必須設定為類似於start_erl.exe
的程式。-e[nv] [<變數>[=<值>]] ...
- 編輯服務的環境區塊。每個指定的環境變數都會新增至系統環境區塊。如果這裡指定的變數名稱與系統範圍環境變數相同,則指定的值會覆寫系統範圍的值。環境變數會透過指定 <變數>=<值> 來新增至此清單,而透過單獨指定 <變數> 來從清單中刪除。環境區塊會自動排序。一個命令中可以指定任意數量的-env
選項。預設值為使用未修改的系統環境區塊(除了兩個新增項目之外,請參閱下方的 環境 章節)。-w[orkdir] [<目錄>]
- Erlang 模擬器的初始工作目錄。預設值為系統目錄。-p[riority] [{low|high|realtime}]
- Erlang 模擬器的優先順序。預設為 Windows 的預設優先順序。{-sn[ame] | -n[ame]} [<節點名稱>]
- Erlang 機器的節點名稱。必須啟用分散式處理。預設為-sname <服務名稱>
。-d[ebugtype] [{new|reuse|console}]
- 指定 Shell 輸出要傳送到哪裡。預設為捨棄 Shell 輸出。僅用於偵錯。-ar[gs] [<有限的 erl 引數>]
- Erlang 模擬器的額外引數。避免使用-noinput
、-noshell
和-sname
/-name
。預設為無額外引數。請記住,服務的 Cookie 檔案不一定與互動式使用者的相同。服務以本機管理員身分執行。請將所有引數放在一個字串中,使用雙引號 (") 指定包含空格的引數字串,如有必要,請使用帶引號的引號 (\") 來指定引數內的引號。-i[nternalservicename] [<內部名稱>]
- 僅允許用於add
。指定服務的 Windows 內部服務名稱,預設情況下,當新增新服務時,會由erlsrv
設定為唯一的值(以原始服務名稱為首碼)。指定此項僅是為了美觀,如果需要執行版本處理,則不建議使用。建立服務後,內部服務名稱即無法變更。內部名稱不應與一般服務名稱混淆,一般服務名稱是用於向erlsrv
識別服務的名稱。-c[omment] [<簡短描述>]
- 指定描述服務的文字註解。此註解會顯示在 Windows 服務管理員中作為服務描述。
erlsrv {start | start_disabled | stop | disable | enable} <服務名稱>
這些命令僅為方便起見而新增,操作服務狀態的正常方法是透過控制台服務小程式。
start
和 stop
命令與服務管理員通訊,以啟動和停止服務。命令會等待直到服務啟動或停止。停用服務時,它不會停止,停用狀態在服務停止之前不會生效。啟用服務會將其設定為自動模式,該模式會在開機時啟動。此命令無法將服務設定為手動模式。
start_disabled
命令會對服務進行操作,無論它是否已啟用/停用或已啟動/停止。它會先啟用服務(無論是否已啟用),然後啟動服務(如果尚未啟動),然後將其停用。結果是一個已停用但已啟動的服務,無論其先前的狀態如何。這對於在版本升級期間暫時啟動服務非常有用。使用 start_disabled
與執行 enable
、start
和 disable
序列的差異在於,在 start_disable
的操作序列期間,會鎖定所有其他 erlsrv
命令,使操作從 erlsrv
使用者的角度來看具有原子性。
erlsrv remove <服務名稱>
完全移除服務及其所有已註冊的選項。它會在移除之前停止。
erlsrv list [<服務名稱>]
如果未指定服務名稱,則會顯示所有 Erlang 服務的簡短清單。如果提供服務名稱,則會顯示該服務的所有選項。
erlsrv help
顯示簡短的說明文字。
環境
ERLSRV_SERVICE_NAME
- 啟動機器的服務名稱。ERLSRV_EXECUTABLE
-erlsrv.exe
的完整路徑,可用於操作服務。當為您的服務定義 Heart 命令時,這會很有用。
重新啟動服務的命令檔如下所示
@echo off
%ERLSRV_EXECUTABLE% stop %ERLSRV_SERVICE_NAME%
%ERLSRV_EXECUTABLE% start %ERLSRV_SERVICE_NAME%
然後將此命令檔設定為 Heart 命令。
環境變數也可用於偵測我們是否作為服務執行,並使 Port 程式正確地對登出時產生的控制事件做出反應(請參閱下一節)。
Port 程式
當程式在服務環境中執行時,它必須處理互動式使用者登出時傳送給系統中每個程式的控制事件。對於在主控台子系統中執行的程式和作為視窗應用程式執行的程式,處理方式不同。在主控台子系統中執行的應用程式(對於 Port 程式很正常)會使用 Win32 函數 SetConsoleCtrlHandler
來註冊一個控制處理常式,該處理常式會針對 CTRL_LOGOFF_EVENT
和 CTRL_SHUTDOWN_EVENT
事件傳回 true
。其他應用程式僅將 WM_ENDSESSION
和 WM_QUERYENDSESSION
轉發到預設的視窗程序。
以下為在 C 中如何設定主控台控制處理常式的簡短範例
#include <windows.h>
/*
** A Console control handler that ignores the log off events,
** and lets the default handler take care of other events.
*/
BOOL WINAPI service_aware_handler(DWORD ctrl){
if(ctrl == CTRL_LOGOFF_EVENT)
return TRUE;
if(ctrl == CTRL_SHUTDOWN_EVENT)
return TRUE;
return FALSE;
}
void initialize_handler(void){
char buffer[2];
/*
* We assume we are running as a service if this
* environment variable is defined.
*/
if(GetEnvironmentVariable("ERLSRV_SERVICE_NAME",buffer,
(DWORD) 2)){
/*
** Actually set the control handler
*/
SetConsoleCtrlHandler(&service_aware_handler, TRUE);
}
}
注意事項
雖然選項以類似 Unix 的格式描述,但選項或命令的大小寫並不重要,並且選項可以使用字元 "/" 和 "-"。
請注意,該程式位於模擬器的 bin
目錄中,而不是 Erlang 根目錄下的 bin
目錄中。這樣做的原因是,在執行中的系統上升級模擬器存在微妙的問題,即新版本的執行階段系統不應覆蓋現有的(並且可能正在使用的)可執行檔。
為了輕鬆操作 Erlang 服務,請將 <erlang_root>\erts-<version>\bin
目錄放入路徑中,而不是 <erlang_root>\bin
。erlsrv
程式可以從 Erlang 內部找到,方法是使用 os:find_executable/1
Erlang 函數。
為了使版本處理正常工作,請使用 start_erl
作為 Erlang 機器的執行程式。如上文所述,服務名稱很重要。