用WinSW注册windows 服务
需要
做windows上应用,我们有基于以下两个主要原因把自己的应用注册成了windows的服务。
- 自动启动, 我们的应用要一直活着,不用写监控脚本什么的,服务崩溃后自动重启,开机自启。
- 后台运行,当然让程序在后台运行的方法有很多,但是比如java进程可能就被人在任务管理中找到干掉了。
方法
把自己的exe或者jar注册成windows的服务有很多方式,比如:
NSSM(Non-Sucking Service Manager)
我们本次选择使用的就是WinSW,这款通过xml配置属性的服务注册工具。
使用准备
在release页面上下载 WinSW-x64.exe
了解配置文件文档
基本命令
命令 描述 install 注册服务 uninstall 卸载服务 start 启动服务 stop 停止服务 restart 重启服务 status 查看服务的状态 比如:
.\WinSW-x64.exe stop .\batch-server.xml
1. 把exe注册成服务
在batch项目要把硬件连接器wincc-contector.exe注册成一个windows服务,实现开机自启。宕机自动重启。
将
WinSW-x64.exe,wincc-contector.exe,配置文件wincc-contector.xml配置文件放在同一目录(也可以用绝对路径)wincc-contector.xml配置内容如下:
<service> <id>WinccConnector</id> <name>WinccConnector</name> <description>WinccConnector</description> <!-- 可以是绝对路径 --> <executable>WinccConnector.exe</executable> <logpath>log</logpath> <log mode="roll-by-size-time"> <sizeThreshold>10240</sizeThreshold> <pattern>yyyyMMdd</pattern> <autoRollAtTime>00:00:00</autoRollAtTime> </log> <!-- 自动重启配置 --> <onfailure action="restart" delay="5 sec"/> <!-- 服务恢复策略 --> <recovery> <!-- 第一次失败后重启,延迟5秒 --> <action type="restart" delay="5 sec"/> <!-- 第二次失败后重启,延迟10秒 --> <action type="restart" delay="10 sec"/> <!-- 第三次失败后重启,延迟10秒 --> <action type="restart" delay="10 sec"/> <!-- 重置恢复策略计数器的时间周期 --> <resetPeriod>1 day</resetPeriod> </recovery> </service>安装,卸载,启动,停止的命令
.\WinSW-x64.exe install .\wincc-connector.xml .\WinSW-x64.exe start .\wincc-connector.xml .\WinSW-x64.exe stop .\wincc-connector.xml .\WinSW-x64.exe uninstall .\wincc-connector.xml
2. 把jar服务注册成服务
需要执行jar所在的目录结构
C:.
| backend.xml
| clj-backend.jar
| config.edn
| mssql-jdbc_auth-9.4.0.x64.dll
| server.db
| WinSW-x64.exe
├───jdk-11.0.22
├───log
backend.xml配置文件内容如下:
<service>
<id>batch-server</id>
<name>Batch 服务</name>
<description>Batch服务</description>
<!-- 确保 PowerShell 的环境与直接运行 java -jar 时一致 -->
<env name="PATH" value="%SystemRoot%\system32\WindowsPowerShell\v1.0;%PATH%"/>
<workingdirectory>C:\CTBatch\batch-server\backend</workingdirectory>
<executable>.\jdk-11.0.22\bin\java.exe</executable>
<arguments> -jar -Dfile.encoding=UTF-8 -Dconf=config.edn -Dclojure.core.async.pool-size=300 .\clj-backend.jar</arguments>
<logpath>log</logpath>
<log mode="roll-by-size-time">
<sizeThreshold>1024</sizeThreshold>
<pattern>yyyyMMdd</pattern>
<autoRollAtTime>00:00:00</autoRollAtTime>
</log>
<!-- 自动重启配置 -->
<onfailure action="restart" delay="10 sec"/>
<!-- 服务恢复策略 -->
<recovery>
<!-- 第一次失败后重启,延迟5秒 -->
<action type="restart" delay="5 sec"/>
<!-- 第二次失败后重启,延迟10秒 -->
<action type="restart" delay="10 sec"/>
<!-- 第三次失败后重启,延迟10秒 -->
<action type="restart" delay="10 sec"/>
<!-- 重置恢复策略计数器的时间周期 -->
<resetPeriod>1 day</resetPeriod>
</recovery>
</service>
操作的命令
.\WinSW-x64.exe install .\backend.xml
.\WinSW-x64.exe start .\backend.xml
.\WinSW-x64.exe stop .\backend.xml
.\WinSW-x64.exe uninstall .\backend.xml
安装完后在windows的服务里能看到如下:



我们关注的日志配置
日志模块的配置官方配置说明在此。
日志路径
<!-- 当前目录下的log里存放日志 --> <logpath>.\log</logpath>日志模式
<log mode="append"/>append: 默认的模式,输出myapp.out.log and myapp.err.log 这两个日志文件
reset:每次服务重启都会把之前的日志清空
none: 忽略日志,不收集日志
roll :这个模式使我们日常使用最多的。详细的解释如下:
<log mode="roll-by-size-time"> <sizeThreshold>10240</sizeThreshold> <pattern>yyyyMMdd</pattern> <autoRollAtTime>00:00:00</autoRollAtTime> </log>这时候的mode有
roll-by-size,roll-by-time,roll-by-size-time,这符合我们日常对日志的需要,就是按日志大小和日期归档日志,最终会生成比如:myapp.20240101.out.log和myapp.20240101.err.log这样的日志。
目前batch的日志
按照上面的配置,log目录下会有四个日志文件
`backend.out.log`: 标注输出log,我们平时用timbre打的日志,会在这里。 `backend.err.log`: 目前batch项目里这里只有告警日志,并没有错误日志(待明确)。 `backend.wrapper.log`: winsw的start,install等控制的操作日志 `clj-backend.log`: 标注输出log,我们平时用timbre打的日志,会在这里。batch的后台用
taoensso.timbre打的日志,因为java启动命令重定向了日志输入,所以日志在jar包同级的log目录里,命名还是clj-backend.log这个我们clojure里指定的文件名。因此,按照上面的配置,batch项目现在大量2份日志。如果要关闭winsw的收集,只需要在xml不配置日志即可。
wincc-connector的日志
这是C#程序打出来的exe文件。log用winsw控制的,按照xml的配置收集了wincc-connector里的日志,但是C#的日志用
dotnet run在控制台能看到,打包后看不到了。
可能会用到
启动和停止要执行的脚本和命令参数不一样
<executable>catalina.sh</executable> <startarguments>jpda run</startarguments> <stopexecutable>catalina.sh</stopexecutable> <stoparguments>stop</stoparguments>启动和停止命令前需要先执行什么
<!-- 主程序启动前需要干点啥 --> <prestart> <executable></executable> <arguments></arguments> <stdoutPath></stdoutPath> <stderrPath></stderrPath> </prestart> <!-- 主程序启动成功后要干啥 --> <poststart> <!-- ... --> </poststart> <!-- 主程序停止前要干啥 --> <prestop> <!-- ... --> </prestop> <!-- 主程序启动后后干啥 --> <poststop> <!-- ... --> </poststop>环境变量,指定活动目录
<env name="HOME" value="C:\CTBatch" />设置服务账号密码
这部分我没有尝试,官方介绍还比较详细,需要的时候可以再深入试用一下。
<serviceaccount> <username>DomainName\UserName</username> <password>Pa55w0rd</password> <allowservicelogon>true</allowservicelogon> <prompt>dialog|console</prompt> <!-- 这是账号密码在哪输入 --> </serviceaccount>
遗留问题
- wincc-connector服务中,C#中打的log,在
dotnet run执行时能看到日志,但是打包成服务后不知道日志在哪里了。 - jar服务,在代码中调用了powershell的命令,用
java -jar启动程序后能读到powershell命令的执行结果,但是注册成服务后执行命令没有报错,但是读不到命令的执行结果。