
📣读完这篇文章里你能收获到

ScheduleMaster是分布式任务调度中心。最简单的理ScheduleMaster,就是对不同的系统里面的调度任务做统一管理的框架。

按这个项目开源作者
HOHO的原话讲就是:没有涉及任何高大上的技术,尽显(低调奢华有内涵)朴实


需要提前准备:isual Studio 2019、.NET Core3.1 SDK、Mysql 5.7(可选)、SQLServer(可选)、PostgreSQL(可选)、Centos(可选)、Docker(可选)。


- 新增worker:按同样方式在项目
Hos.ScheduleMaster.QuartzHost,配置IdentityName、IP、Port即可,worker在启动后会把自己的信息注入到数据库中,在master中可以看到。
- 快速发布小贴士:windows平台下用powershell执行脚本publish.ps1快速发布到d:/sm-publish目录,linux平台下执行脚本sh publish.sh快速发布到/home/sm-publish目录。
初始用户名
admin,密码111111

worker1节点:找到worker的发布目录,执行命令dotnet Hos.ScheduleMaster.QuartzHost.dll --urls http://*:30001启动程序,打开浏览器输入ip和端口会看到一个欢迎页面,表示worker已启动成功。
worker2节点:修改worker下的appsettings.json文件为worker2的配置(如果发布前已经修改可跳过),执行命令dotnet Hos.ScheduleMaster.QuartzHost.dll --urls http://*:30002启动程序.



为了方便业务系统更好的接入调度系统,创建任务不仅可以在控制台中实现,系统也提供了WebAPI供业务系统使用代码接入,这种方式对延时任务来说尤其重要。
对于开放接口来说,使用签名验证已经是必不可少的一环,这是保证系统安全性的重要手段。看一下核心对接流程:
ms_auth_user值。ms_auth_secret值,计算规则:按{用户名}{hash(密码)}{用户名}的格式拼接得到字符串str,然后再对str做一次hash运算即得到最终秘钥,hash函数是小写的32位MD5算法。代码示例:
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("ms_auth_user", "admin");
client.DefaultRequestHeaders.Add("ms_auth_secret", SecurityHelper.MD5($"admin{SecurityHelper.MD5("111111")}}admin"));
签名验证这块设计的比较简单,具体源码逻辑可以参考
Hos.ScheduleMaster.Web.Filters.AccessControlFilter。
所有接口采用统一的返回格式,字段如下:
| 参数名称 | 参数类型 | 说明 |
|---|---|---|
| Success | bool | 是否成功 |
| Status | int | 结果状态,0-请求失败 1-请求成功 2-登录失败 3-参数异常 4-数据异常 |
| Message | string | 返回的消息 |
| Data | object | 返回的数据 |
示例:
接口地址:http://yourip:30000/api/task/create
请求类型:POST
参数格式:application/x-www-form-urlencoded
返回结果:创建成功返回任务id
参数列表:
| 参数名称 | 参数类型 | 是否必填 | 说明 |
|---|---|---|---|
| MetaType | int | 是 | 任务类型,这里固定是2 |
| Title | string | 是 | 任务名称 |
| RunLoop | bool | 是 | 是否按周期执行 |
| CronExpression | string | 否 | cron表达式,如果RunLoop为true则必填 |
| StartDate | DateTime | 是 | 任务开始时间 |
| EndDate | DateTime | 否 | 任务停止时间,为空表示不限停止时间 |
| Remark | string | 否 | 任务描述说明 |
| HttpRequestUrl | string | 是 | 请求地址 |
| HttpMethod | string | 是 | 请求方式,仅支持GET\POST\PUT\DELETE |
| HttpContentType | string | 是 | 参数格式,仅支持application/json和application/x-www-form-urlencoded |
| HttpHeaders | string | 否 | 自定义请求头,ScheduleParam列表的json字符串 |
| HttpBody | string | 是 | 如果是json格式参数,则是对应参数的json字符串;如果是form格式参数,则是对应ScheduleParam列表的json字符串。 |
| Keepers | List | 否 | 监护人id |
| Nexts | List | 否 | 子级任务id |
| Executors | List | 否 | 执行节点名称 |
| RunNow | bool | 否 | 创建成功是否立即启动 |
代码示例:
HttpClient client = new HttpClient();
List<KeyValuePair<string, string>> args = new List<KeyValuePair<string, string>>();
args.Add(new KeyValuePair<string, string>("MetaType", "2"));
args.Add(new KeyValuePair<string, string>("RunLoop", "true"));
args.Add(new KeyValuePair<string, string>("CronExpression", "22 0/8 * * * ?"));
args.Add(new KeyValuePair<string, string>("Remark", "By Xunit Tester Created"));
args.Add(new KeyValuePair<string, string>("StartDate", DateTime.Today.ToString("yyyy-MM-dd HH:mm:ss")));
args.Add(new KeyValuePair<string, string>("Title", "Http接口测试任务"));
args.Add(new KeyValuePair<string, string>("HttpRequestUrl", "http://localhost:56655/api/1.0/value/jsonpost"));
args.Add(new KeyValuePair<string, string>("HttpMethod", "POST"));
args.Add(new KeyValuePair<string, string>("HttpContentType", "application/json"));
args.Add(new KeyValuePair<string, string>("HttpHeaders", "[]"));
args.Add(new KeyValuePair<string, string>("HttpBody", "{ \"Posts\": [{ \"PostId\": 666, \"Title\": \"tester\", \"Content\":\"testtesttest\" }], \"BlogId\": 111, \"Url\":\"qweqrrttryrtyrtrtrt\" }"));
HttpContent reqContent = new FormUrlEncodedContent(args);
var response = await client.PostAsync("http://localhost:30000/api/Task/Create", reqContent);
var content = await response.Content.ReadAsStringAsync();
Debug.WriteLine(content);
示例:
接口地址:http://yourip:30000/api/delaytask/create
请求类型:POST
参数格式:application/x-www-form-urlencoded
返回结果:创建成功返回任务id
参数列表:
| 参数名称 | 参数类型 | 是否必填 | 说明 |
|---|---|---|---|
| SourceApp | string | 是 | 来源 |
| Topic | string | 是 | 主题 |
| ContentKey | string | 是 | 业务关键字 |
| DelayTimeSpan | int | 是 | 延迟相对时间 |
| DelayAbsoluteTime | DateTime | 是 | 延迟绝对时间 |
| NotifyUrl | string | 是 | 回调地址 |
| NotifyDataType | string | 是 | 回调参数格式,仅支持application/json和application/x-www-form-urlencoded |
| NotifyBody | string | 是 | 回调参数,json格式字符串 |
代码示例:
for (int i = 0; i < 5; i++)
{
int rndNum = new Random().Next(20, 500);
List<KeyValuePair<string, string>> args = new List<KeyValuePair<string, string>>();
args.Add(new KeyValuePair<string, string>("SourceApp", "TestApp"));
args.Add(new KeyValuePair<string, string>("Topic", "TestApp.Trade.TimeoutCancel"));
args.Add(new KeyValuePair<string, string>("ContentKey", i.ToString()));
args.Add(new KeyValuePair<string, string>("DelayTimeSpan", rndNum.ToString()));
args.Add(new KeyValuePair<string, string>("DelayAbsoluteTime", DateTime.Now.AddSeconds(rndNum).ToString("yyyy-MM-dd HH:mm:ss")));
args.Add(new KeyValuePair<string, string>("NotifyUrl", "http://localhost:56655/api/1.0/value/delaypost"));
args.Add(new KeyValuePair<string, string>("NotifyDataType", "application/json"));
args.Add(new KeyValuePair<string, string>("NotifyBody", "{ \"Posts\": [{ \"PostId\": 666, \"Title\": \"tester\", \"Content\":\"testtesttest\" }], \"BlogId\": 111, \"Url\":\"qweqrrttryrtyrtrtrt\" }"));
HttpContent reqContent = new FormUrlEncodedContent(args);
var response = await client.PostAsync("http://localhost:30000/api/DelayTask/Create", reqContent);
var content = await response.Content.ReadAsStringAsync();
Debug.WriteLine(content);
}