.net core+topshelf+quartz创建windows定时任务服务
程序员文章站
2022-07-05 11:18:11
.net core+topshelf+quartz创建windows定时任务服务 准备工作 创建.net core 控制台应用程序,这里不做过多介绍 添加TopShelf包:TopShelf; 添加Quartz包:Quartz、Quartz.Plugins; 添加依赖注入包:Microsoft.Ex ......
.net core+topshelf+quartz创建windows定时任务服务
准备工作
- 创建.net core 控制台应用程序,这里不做过多介绍
- 添加topshelf包:topshelf;
- 添加quartz包:quartz、quartz.plugins;
- 添加依赖注入包:microsoft.extensions.dependencyinjection;
- 添加读取配置文件包:microsoft.extensions.configuration.json;
- 添加访问数据库包:microsoft.entityframeworkcore;
- 添加日志包:serilog、serilog.sinks.console、serilog.sinks.file
配置quartz
- 创建appsettings.json文件,右键文件属性,并更改属性为始终复制 内容
{ "quartz": { "scheduler": { "instancename": "job" }, "threadpool": { "type": "quartz.simpl.simplethreadpool, quartz", "threadpriority": "normal", "threadcount": 10 }, "plugin": { "jobinitializer": { "type": "quartz.plugin.xml.xmlschedulingdataprocessorplugin, quartz.plugins", "filenames": "quartz_jobs.xml" } } } }
- 创建quartzoption 类
namespace job { public class quartzoption { public quartzoption(iconfiguration config) { if (config == null) { throw new argumentnullexception(nameof(config)); } var section = config.getsection("quartz"); section.bind(this); } public scheduler scheduler { get; set; } public threadpool threadpool { get; set; } public plugin plugin { get; set; } public namevaluecollection toproperties() { var properties = new namevaluecollection { ["quartz.scheduler.instancename"] = scheduler?.instancename, ["quartz.threadpool.type"] = threadpool?.type, ["quartz.threadpool.threadpriority"] = threadpool?.threadpriority, ["quartz.threadpool.threadcount"] = threadpool?.threadcount.tostring(), ["quartz.plugin.jobinitializer.type"] = plugin?.jobinitializer?.type, ["quartz.plugin.jobinitializer.filenames"] = plugin?.jobinitializer?.filenames }; return properties; } } public class scheduler { public string instancename { get; set; } } public class threadpool { public string type { get; set; } public string threadpriority { get; set; } public int threadcount { get; set; } } public class plugin { public jobinitializer jobinitializer { get; set; } } public class jobinitializer { public string type { get; set; } public string filenames { get; set; } } }
添加一个job
namespace job { public class syncjob : ijob { private readonly iservice _service; public syncjob(iservice service) { _service = service; } public async task execute(ijobexecutioncontext context) { log.information("同步开始..."); _service.dosomething(); } } }
实现ijobfactory
namespace job { public class jobfactory : ijobfactory { protected readonly iserviceprovider container; public jobfactory(iserviceprovider container) { container = container; } public ijob newjob(triggerfiredbundle bundle, ischeduler scheduler) { return container.getservice(bundle.jobdetail.jobtype) as ijob; } public void returnjob(ijob job) { (job as idisposable)?.dispose(); } } }
创建quartz调度的配置文件 quartz_jobs.xml
文件名与appsetting中的quartz.plugin.jobinitializer.filenames 保持一致
<?xml version="1.0" encoding="utf-8"?> <job-scheduling-data xmlns="http://quartznet.sourceforge.net/jobschedulingdata" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" version="2.0"> <processing-directives> <overwrite-existing-data>true</overwrite-existing-data> </processing-directives> <schedule> <job> <name>syncjob</name> <group>syncgroup</group> <description>数据同步任务</description> <job-type>mille.job.syncjob, mille.job</job-type> <durable>true</durable> <recover>false</recover> </job> <trigger> <cron> <name>synctrigger</name> <group>syncgroup</group> <description>同步触发器</description> <job-name>syncdjob</job-name> <job-group>syncgroup</job-group> <!--每晚23:50跑一次,具体参见cron表达式--> <cron-expression>0 50 23 ? * *</cron-expression> </cron> </trigger> <!--<trigger> <simple> <name>synctrigger</name> <group>syncgroup</group> <description>数据同步触发器</description> <job-name>syncjob</job-name> <job-group>syncgroup</job-group> <repeat-count>-1</repeat-count> 2s跑一次 <repeat-interval>2000</repeat-interval> </simple> </trigger>--> </schedule> </job-scheduling-data>
添加一个类,此类用户服务启动调用
namespace job { public class syncservice { public async task startasync() { var provider = registerservices(); scheduler = provider.getservice(typeof(ischeduler)) as ischeduler; await scheduler.start(); log.information("quartz调度已启动..."); } public async task stopasync() { await scheduler.shutdown(); log.information("quartz调度结束..."); log.closeandflush(); } #region utils private ischeduler scheduler { get; set; } private static serviceprovider registerservices() { log.information("配置依赖注入..."); var configuration = readfromappsettings(); var services = new servicecollection(); #region services.addscoped<syncservice>(); services.adddbcontext<datacontext>(opt => opt.usemysql(configuration.getconnectionstring("connstr"))); services.addscoped<iservice,service>(); #endregion #region quartz log.information("配置quartz..."); services.addscoped<ijobfactory, jobfactory>(); services.addsingleton(service => { var option = new quartzoption(configuration); var sf = new stdschedulerfactory(option.toproperties()); var scheduler = sf.getscheduler().result; scheduler.jobfactory = service.getservice<ijobfactory>(); return scheduler; }); services.addscoped<syncjob>(); //此处不能写成services.addscoped<ijob,syncjob>(); 会造成在找不到syncjob #endregion var provider = services.buildserviceprovider(); return provider; } private static iconfigurationroot readfromappsettings() { //读取appsettings.json return new configurationbuilder() .setbasepath(directory.getcurrentdirectory()) .addjsonfile("appsettings.json", false) .build(); } #endregion } }
配置topshelf
详情参见
namespace job { public class program { public static void main(string[] args) { instancelog(); var rc = hostfactory.run(x => { x.service<syncservice>(s => { s.constructusing(name => new syncservice()); s.whenstarted(async tc => await tc.startasync()); //调用此方法前勿有太多操作,会造成服务启动失败 s.whenstopped(async tc => await tc.stopasync()); }); x.runaslocalsystem(); x.setdescription("syncjob description"); x.setdisplayname("syncjob displayname"); x.setservicename("syncjob servicename"); }); var exitcode = (int)convert.changetype(rc, rc.gettypecode()); environment.exitcode = exitcode; } private static void instancelog() { //配置serilog var template = "{timestamp:hh:mm:ss} [{level:u3}] {message}{newline}{exception}"; log.logger = new loggerconfiguration() .writeto.file(path: "logs/log.txt", outputtemplate: template, rollinginterval: rollinginterval.day) .writeto.console(logeventlevel.information) .createlogger(); } } }
然后在项目文件中加上项目的运行环境相关配置
<propertygroup> <outputtype>exe</outputtype> <targetframework>netcoreapp3.0</targetframework> <runtimeidentifier>win7-x64</runtimeidentifier>//不同的环境rid不同 </propertygroup>
运行
编译项目之后,进入到/bin/debug/netcoreapp3.0/win7-x64目录,在此处以管理员运行cmd,然后执行 依次job.exe install 安装服务, job.exe start 启动服务
如果遇到启动服务时报 1053错误:服务没有及时响应启动或控制请求。检查start函数调用之前是否还有其他操作,如有,请将这些操作移动到start调用后执行;本人就是由于在start之前执行了依赖注入等操作,导致服务启动失败,故写下这篇文章
此文章有部分借鉴其他博主的博客,如有侵权,请联系删除
上一篇: Linux服务器相关信息查询
推荐阅读
-
C#基于Quartz.NET实现任务调度并部署Windows服务
-
使用 Topshelf 组件一步一步创建 Windows 服务 (2) 使用Quartz.net 调度
-
用.NET创建Windows服务的方法第1/2页
-
基于C#&.net2.0的windows服务创建与安装
-
在windows10上创建ASP.NET mvc5+Memcached服务
-
Window服务基于Quartz.Net组件实现定时任务调度(二)
-
C#添加Windows服务 定时任务
-
在windows10上创建ASP.NET mvc5+Memcached服务
-
.net core+topshelf+quartz创建windows定时任务服务
-
使用 Topshelf 组件一步一步创建 Windows 服务 (2) 使用Quartz.net 调度