もくてき
Go言語で作成したプログラムを何とかしてWindows Service化したい!
できることなら、同じソースコードを使用して、LinuxのSystemdのServiceにもしたい!
なんてことを考えて探してみた所、とても便利なパッケージがありました。
Linuxの方は何とでもなるので、一先ずWindows Service化を試してみました。
使用するパッケージ
kardianos/service というパッケージです。
ServiceのInstall,Uninstall,Start,Stopができるパッケージで、Windows XP以上, Linux(systemd | Upstart | SysV), OSX Launchdに対応しているようです。
使い方
https://github.com/kardianos/service/tree/master/example
ここに、作成例が4種類公開されてます。
自分でも何か良いサンプルになるものを書いてみようとしてみはみましたが、結局の所は↑のexampleのようなものが出来上がりました。
https://github.com/mako2kano/go_example_service/blob/master/main.go
Windowsにインストールしてみる
↑のgo_example_serviceは、windows環境でgo buildするとgo_example_service.exeができます。
Powershellをadminで起動して、"go_example_service.exe install"と打ってenterすると、インストールできるはずです。
インストール後にServicesを起動してみると、確かにインストールされてます。
"go_example_service.exe uninstall"でアンインストールです。
Windowsで動かしてみる
"go_example_service.exe start"すると、Start()メソッドが呼ばれて動き出します。
例ではStart()の中で、↓のRun()を読んでるので、1秒に1回ログを出力してます。
func (e *exarvice) Run() error {
logger.Info("Exarvice Start !!!")
ticker := time.NewTicker(1 * time.Second)
for {
select {
case tm := <-ticker.C:
logger.Infof("Still running at %v", tm)
case <-e.exit:
ticker.Stop()
logger.Info("Exarvice Stop ...")
return nil
}
}
}
startした状態で、Event viewerを見てみると、Windows LogsのApplicationのところに、logger.Infof()やlogger.info()で出力したMessageが出てます。
"go_example_service.exe stop"で停止します。
参考にしたページ
goでWindows serviceを作成する
この記事を最初に見つけて、試してみようと思いましたが、記事が古いせいか使っているパッケージも古く、使い方も若干違うようでしたので、記事を書いてみました。
注意すること!!!
tickerを5秒にしたら、startが出来なくなりました。
Errorの内容は、「Failed to start service. The service did not respond to the start or control request in a timely」で、この現象はserviceをinstall後にStartした時のみ出てました。Run()で動かした場合は出ませんでした。
理由が全く分からなくて、書き直したり動作確認してる中で、tickerを1秒にしたらstart出来るようになりました。
具体的に何秒かは調べてませんが、serviceを開始するにあたって、長い間だんまりだとタイムアウトして応答無しと判断されてしまうようです。
原因?と回避策(2018年6月14日追記)
Service Control Managerのstartのtimeoutは30000msらしいです。
つまり30秒です。
A timeout was reached (30000 milliseconds) while waiting for the Exarvice (Go Service Example) service to connect.
解せぬ。
Goで作成したプログラムがstartするまでに25秒以上はかかっていて、その後更にtimerで5秒以上待ってたのが原因なのでしょうか?
回避策としては、regeditを起動して、HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\ControlのServicesPipeTimeoutの値を30000から60000等に変更すれば良いようです。
ServicesPipeTimeoutが無い場合は作成します。
※この設定は再起動されるまで反映されないです。