Admin Core

任务调度

任务调度用于定时执行预设任务,如定时发送邮件、定时调用 Grpc 方法和服务方法等。

任务调度用于定时执行预设任务,如定时发送邮件、定时调用 Grpc 方法和服务方法等。

任务调度配置

appsettings.json 中添加以下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
"TaskScheduler": {
// 进程启动信息
"ProcessStartInfo": {
// Grpcurl.exe 路径
"FileName": "C:/grpcurl_1.8.7/grpcurl",
// 工作目录
"WorkingDirectory": ""
},
// 告警邮件
"AlerEmail": {
// 是否启用
"Enable": true,
// 邮件地址,多个地址用逗号分隔
"Address": ""
},
// 模块列表
"Modules": [
{
// 模块名称
"Name": "admin",
// HTTP 请求地址
"HttpUrl": "http://localhost:18010",
// Grpc 请求地址
"GrpcUrl": "http://localhost:18011"
}
]
}

下载 Grpcurl

下载地址:https://github.com/fullstorydev/grpcurl/releases/tag/v1.8.7

建议:使用 grpcurl v1.8.7 版本,v1.8.8 及以上版本存在调用 Grpc 方法异常的问题。

告警邮件配置

appsettings.json 中添加以下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
"Email": {
"Host": "smtp.exmail.qq.com",
"Port": 465,
"UseSsl": true,
"UserName": "",
"Password": "",
"FromEmail": {
"Name": "",
"Address": ""
},
"ToEmail": {
"Name": "",
"Address": ""
}
}

添加任务调度服务

Program.cs 中添加任务调度服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
using Microsoft.Extensions.DependencyInjection;
using ZhonTai.Admin.Core;
using ZhonTai.Admin.Core.Startup;
using ZhonTai.Admin.Tools.TaskScheduler;
using FreeScheduler;
using AdminDbKeys = ZhonTai.Admin.Core.Consts.DbKeys;
using ZhonTai.Admin.Core.Db;
using System;
using ZhonTai.Admin.Services.TaskScheduler;
using ZhonTai.Admin.Core.Extensions;
using Mapster;
using ZhonTai;
using Microsoft.Extensions.Options;
using System.Linq;

new HostApp(new HostAppOptions()
{
// 配置 FreeSql
ConfigureFreeSql = (freeSql, dbConfig) =>
{
// 同步任务调度结构
if (dbConfig.Key == AdminDbKeys.TaskDb)
{
freeSql.SyncSchedulerStructure(dbConfig, TaskSchedulerServiceExtensions.ConfigureScheduler);
}
},
// 配置前置服务
ConfigurePreServices = context =>
{
// 任务调度配置
context.Services.Configure<TaskSchedulerConfig>(context.Configuration.GetSection("TaskScheduler"));
},
// 配置后置服务
ConfigurePostServices = context =>
{
// 添加任务调度,默认使用权限库作为任务调度库
context.Services.AddTaskScheduler(AdminDbKeys.TaskDb, options =>
{
options.ConfigureFreeSql = TaskSchedulerServiceExtensions.ConfigureScheduler;

// 配置任务调度
options.ConfigureFreeSchedulerBuilder = freeSchedulerBuilder =>
{
static void OnExecuting(TaskInfo task)
{
// 执行 Grpc 任务
if (task.Topic?.StartsWith("[shell]") == true)
{
var taskSchedulerConfig = AppInfo.GetRequiredService<IOptions<TaskSchedulerConfig>>().Value;
var jsonArgs = JToken.Parse(task.Body);
var shellArgs = jsonArgs.Adapt<ShellArgs>();
var modeulName = jsonArgs["moduleName"]?.ToString();
var grpcAddress = "";

if (modeulName.NotNull())
{
grpcAddress = taskSchedulerConfig.Modules?
.Where(m => m.Name.Equals(modeulName, StringComparison.OrdinalIgnoreCase))
.FirstOrDefault()?.GrpcUrl;
}

TaskSchedulerServiceExtensions.ExecuteGrpc(task, grpcAddress);
}
else
{
// 执行 Service 任务
switch (task.Topic)
{
// 匹配模块任务示例
case TaskNames.ModuleTaskName:
Task.Run(async () =>
{
using var scope = AppInfo.ServiceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope();
var moduleService = scope.ServiceProvider.GetRequiredService<IModuleService>();
var dics = JsonConvert.DeserializeObject<Dictionary<string, string>>(task.Body);
var moduleId = dics["moduleId"];
var result = await moduleService.GetAsync(moduleId.ToLong());

if (result.Success)
{
// 完成并结束任务
task.Status = TaskStatus.Completed;
}
}).Wait();
break;
}
}
}

freeSchedulerBuilder
.OnExecuting(task => OnExecuting(task))
.OnExecuted((task, taskLog) =>
{
try
{
if (!taskLog.Success)
{
var taskService = AppInfo.GetRequiredService<TaskService>();
var taskInfo = taskService.GetAsync(task.Id).Result;

// 失败重试
TaskSchedulerServiceExtensions.FailedRetry(taskInfo, task, taskLog, OnExecuting);

// 发送告警邮件
TaskSchedulerServiceExtensions.SendAlarmEmail(taskInfo, task, taskLog);
}
}
catch (Exception ex)
{
AppInfo.Log.Error(ex);
}
});
};
});
}
}).Run(args);

public partial class Program { }

添加任务

方式一:任务调度界面

  1. 打开任务调度界面,点击新增按钮
  2. 在任务参数输入框下方点击 Json 按钮,打开 Json 编辑器
  3. 点击 Shell 按钮,在 Json 编辑器中:
    • YourNamespace.YourGrpcService/YourMethod 替换为实际调用的 Grpc 方法
    • ModuleName 修改为 Grpc 请求地址所在的模块名称
    • 点击确定保存 Json
  4. 报警邮件、失败重试次数、重试间隔(秒)为可选配置,根据实际需求配置
  5. 定时类型选择 Cron 表达式并配置定时参数后,点击确定按钮添加任务

方式二:模块服务中添加任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
namespace MyCompanyName.MyProjectName.Api.Services.Module;

/// <summary>
/// 模块服务
/// </summary>
[DynamicApi(Area = ApiConsts.AreaName)]
public class ModuleService : BaseService, IModuleService, IDynamicApi
{
private readonly Lazy<Scheduler> _scheduler;

public ModuleService(Lazy<Scheduler> scheduler)
{
_scheduler = scheduler;
}

/// <summary>
/// 执行任务
/// </summary>
public void ExecuteTask()
{
var scheduler = _scheduler.Value;

// 方式1:添加任务组,第一组每次间隔15秒,第二组每次间隔2分钟
scheduler.AddTask(TaskNames.ModuleTaskName, JsonConvert.SerializeObject(new
{
moduleId = 1
}), new int[] { 15, 15, 120, 120 });

// 方式2:添加任务,每次间隔15秒
scheduler.AddTask(TaskNames.ModuleTaskName, JsonConvert.SerializeObject(new
{
moduleId = 1
}), 2, 15);

// 方式3:无限循环任务,每次间隔10分钟
scheduler.AddTask(TaskNames.ModuleTaskName, JsonConvert.SerializeObject(new
{
moduleId = 1
}), -1, 600);

// 方式4:每天凌晨执行一次
scheduler.AddTaskRunOnDay(TaskNames.ModuleTaskName, JsonConvert.SerializeObject(new
{
moduleId = 1
}), 1, "0:00:00");

// 方式5:每周一晚上23:30执行一次,0为周日,1-6为周一至周六
scheduler.AddTaskRunOnWeek(TaskNames.ModuleTaskName, JsonConvert.SerializeObject(new
{
moduleId = 1
}), 1, "1:23:30:00");

// 方式6:每月1号下午16:00执行一次,-1为每月最后一日
scheduler.AddTaskRunOnMonth(TaskNames.ModuleTaskName, JsonConvert.SerializeObject(new
{
moduleId = 1
}), 1, "1:16:00:00");

// 方式7:自定义 Cron 表达式,从0秒开始每10秒执行一次
scheduler.AddTaskCustom(TaskNames.ModuleTaskName, JsonConvert.SerializeObject(new
{
moduleId = 1
}), "0/10 * * * * ?");
}
}

#中台 #中台/配置文件 #中台/特性注解 #中台/新建接口项目 #中台/分布式微服务