使用ServiceSelf解決.NET應用程序做服務的難題

1 ServiceSelf

.NET 泛型主機的應用程序提供自安裝爲服務進程的能力,支持windows和linux平臺。

功能

  • 自我服務安裝
  • 自我服務卸載
  • 自我服務日誌監聽

2 自我服務安裝

雖然.NetCore提供了Microsoft.Extensions.Hosting.SystemdMicrosoft.Extensions.Hosting.WindowsServices兩個服務生命週期包,但在服務安裝這塊目前還非常不便:在windows平臺,需要管理員身份使用sc.exe工具來安裝服務;在linux平臺,需要自己手動寫服務單元文件和使用systemctl加載服務。不常用的sc和服務單元文件的內容知識,就像學了外語之後又長期不用外語的我們一樣,時間一久就忘記。而且windows服務進程的默認工作目錄是%SystemRoot%\System32,在沒有日誌組件的幫助下,sc.exe安裝的服務在運行後我們可能就掉到工作目錄的坑裏,影響包括但不限於配置文件的讀取、asp.netcore的ContentRoot、wwwroot靜態文件等。

ServiceSelf提供自我服務安裝的能力,它提供了windows服務和linux的systemd服務的公共參,同時另外提供windows獨有的服務配置和systemd獨有的完整服務配置,此外還解決了windows服務沒有工作目錄配置的缺陷。

現在,你可以在使用ServiceSelf描述服務:

var serviceName = "myapp";
var serviceOptions = new ServiceOptions
{
    Arguments = new[] { new Argument("key", "value") },
    Description = "這是演示示例應用",
};
serviceOptions.Linux.Service.Restart = "always";
serviceOptions.Linux.Service.RestartSec = "10";
serviceOptions.Windows.DisplayName = "演示示例";
serviceOptions.Windows.FailureActionType = WindowsServiceActionType.Restart;

// serviceName和serviceOptions甚至可以爲null
if (Service.UseServiceSelf(args, serviceName, serviceOptions))
{
    var host = Host.CreateDefaultBuilder(args)
        // 爲Host配置UseServiceSelf()
        .UseServiceSelf()                     
        .Build();

    host.Run();
}

然後在控制檯下以管理員或root身份執行如下命令:

./myapp start // 安裝並啓動服務

3 自我服務卸載

在控制檯下以管理員或root身份執行如下命令:

./myapp stop // 停止並刪除服務

4 自我服務日誌監聽

雖然有文件日誌、大型的日誌採集平臺或框架等,但他們也取代不了控制檯實時顯示的日誌,相反他們是互補的。控制檯模式啓動時,我們很容易直接在控制檯看到實時日誌的打印,但安裝爲服務後,查看控制檯日誌變得不容易或無法實現,在linux平臺有journalctl,它是基於管道的,它無法知道一條日誌內容的邊界,很難把符合過濾特徵的日誌完整顯示;windows平臺有session隔離機制,服務進程和桌面用戶進程不在同一個session,所以桌面用戶看不到服務進程的控制檯,也沒有管道可以重定向來讀取服務進程的控制輸出。

ServiceSelf爲服務進程集成了"自研的"的基於管道傳輸的Google.Protobuf結構化日誌提供者,在監聽者開啓監聽之後,這個日誌提供者纔會工作,把結構化的日誌傳輸給監聽者,監聽者可以使用關鍵詞來過濾得到完整的一條結構化日誌,而不是隻過濾得一條日誌內容的某一行或幾行,再把完整的結構化日誌打印到監聽者的Console上。也就是它不會在服務進程上讓日誌無腦地輸出到串行化輸出的低性能控制檯,也不會讓服務進程在沒有監聽者的情況下無腦的輸出Google.Protobuf結構化日誌,即這個日誌組件對服務進程沒有性能影響。

之所以要自己實現基於管道傳輸的Google.Protobuf結構化日誌提供者,而不直接使用Microsoft的EventSourceLoggerProvider,是因爲跨進程讀取日誌時需要依賴Microsoft.Diagnostics.Tracing.TraceEvent,這個包非常大而全,其依賴項也特別多,而我們僅僅日誌這一小功能而已。

由於監聽者與服務進程是同一個應用程序的不同進程,當應用程序的OutputType是WinExe模式且運行在windows時,這時候是沒有Console的,ServiceSelf做爲監聽者角色時會檢測和動態創建Console然後將日誌輸出到Console。

現在輸入logs子命令,就在Console上輸出服務進程的實時日誌:

./myapp logs // 控制檯輸出服務的日誌
./myapp logs filter="key words" // 控制檯輸出匹配了"key words"的服務的日誌

5 後記

ServiceSelf在api設計上十分精煉,你只要關注Service.UseServiceSelf()IHostBuilder.UseServiceSelf()兩個函數即可,但可以爲你的服務進程提供非常完整的解決方案,您可以到 github上關注此項目。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章