mirror of
https://github.com/anjoy8/Blog.Core.git
synced 2024-09-20 23:48:27 +08:00
add quartz.net
增加 任务调度 quartz.net
This commit is contained in:
parent
9a53256317
commit
403b30a3ed
|
@ -18,6 +18,9 @@
|
|||
<PackageReference Include="StackExchange.Redis" Version="2.0.601" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.6.0" />
|
||||
|
||||
<PackageReference Include="Serilog" Version="2.9.0" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="3.2.0" />
|
||||
<PackageReference Include="Serilog.Sinks.RollingFile" Version="3.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
44
Blog.Core.Common/LogHelper/Seri/SerilogServer.cs
Normal file
44
Blog.Core.Common/LogHelper/Seri/SerilogServer.cs
Normal file
|
@ -0,0 +1,44 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Serilog;
|
||||
using Serilog.Events;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Blog.Core.Common.LogHelper
|
||||
{
|
||||
public class SerilogServer
|
||||
{
|
||||
/// <summary>
|
||||
/// 记录日常日志
|
||||
/// </summary>
|
||||
/// <param name="filename"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="info"></param>
|
||||
public static void WriteLog(string filename, string message, string info)
|
||||
{
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
.MinimumLevel.Debug()
|
||||
.MinimumLevel.Override("Microsoft", LogEventLevel.Error)
|
||||
.WriteTo.File(Path.Combine($"log/Information/{filename}/", ".txt"), rollingInterval: RollingInterval.Day)
|
||||
.CreateLogger();
|
||||
Log.Information(message+ info, info);
|
||||
Log.CloseAndFlush();
|
||||
}
|
||||
/// <summary>
|
||||
/// 记录异常日志
|
||||
/// </summary>
|
||||
/// <param name="filename"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="ex"></param>
|
||||
public static void WriteErrorLog(string filename,string message, Exception ex)
|
||||
{
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
.MinimumLevel.Debug()
|
||||
.MinimumLevel.Override("Microsoft", LogEventLevel.Error)
|
||||
.WriteTo.File(Path.Combine($"log/Error/{filename}/",".txt"),rollingInterval:RollingInterval.Day)
|
||||
.CreateLogger();
|
||||
Log.Error(ex, message);
|
||||
Log.CloseAndFlush();
|
||||
}
|
||||
}
|
||||
}
|
14
Blog.Core.IRepository/ITasksQzRepository.cs
Normal file
14
Blog.Core.IRepository/ITasksQzRepository.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
|
||||
using Blog.Core.IRepository.Base;
|
||||
using Blog.Core.Model.Models;
|
||||
|
||||
namespace Blog.Core.IRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// ITasksQzRepository
|
||||
/// </summary>
|
||||
public interface ITasksQzRepository : IBaseRepository<TasksQz>
|
||||
{
|
||||
}
|
||||
}
|
||||
|
16
Blog.Core.IServices/ITasksQzServices.cs
Normal file
16
Blog.Core.IServices/ITasksQzServices.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
|
||||
using Blog.Core.IServices.BASE;
|
||||
using Blog.Core.Model.Models;
|
||||
|
||||
namespace Blog.Core.IServices
|
||||
{
|
||||
/// <summary>
|
||||
/// ITasksQzServices
|
||||
/// </summary>
|
||||
public interface ITasksQzServices :IBaseServices<TasksQz>
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
78
Blog.Core.Model/Models/TasksQz.cs
Normal file
78
Blog.Core.Model/Models/TasksQz.cs
Normal file
|
@ -0,0 +1,78 @@
|
|||
using SqlSugar;
|
||||
using System;
|
||||
|
||||
namespace Blog.Core.Model.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// 任务计划表
|
||||
/// </summary>
|
||||
public class TasksQz : RootEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// 任务名称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDataType = "nvarchar", Length = 200, IsNullable = true)]
|
||||
public string Name { get; set; }
|
||||
/// <summary>
|
||||
/// 任务分组
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDataType = "nvarchar", Length = 200, IsNullable = true)]
|
||||
public string JobGroup { get; set; }
|
||||
/// <summary>
|
||||
/// 任务运行时间表达式
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDataType = "nvarchar", Length = 200, IsNullable = true)]
|
||||
public string Cron { get; set; }
|
||||
/// <summary>
|
||||
/// 任务所在DLL对应的程序集名称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDataType = "nvarchar", Length = 200, IsNullable = true)]
|
||||
public string AssemblyName { get; set; }
|
||||
/// <summary>
|
||||
/// 任务所在类
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDataType = "nvarchar", Length = 200, IsNullable = true)]
|
||||
public string ClassName { get; set; }
|
||||
/// <summary>
|
||||
/// 任务描述
|
||||
/// </summary>
|
||||
public string Remark { get; set; }
|
||||
/// <summary>
|
||||
/// 执行次数
|
||||
/// </summary>
|
||||
public int RunTimes { get; set; }
|
||||
/// <summary>
|
||||
/// 开始时间
|
||||
/// </summary>
|
||||
public DateTime? BeginTime { get; set; }
|
||||
/// <summary>
|
||||
/// 结束时间
|
||||
/// </summary>
|
||||
public DateTime? EndTime { get; set; }
|
||||
/// <summary>
|
||||
/// 触发器类型(0、simple 1、cron)
|
||||
/// </summary>
|
||||
public int TriggerType { get; set; }
|
||||
/// <summary>
|
||||
/// 执行间隔时间, 秒为单位
|
||||
/// </summary>
|
||||
public int IntervalSecond { get; set; }
|
||||
/// <summary>
|
||||
/// 是否启动
|
||||
/// </summary>
|
||||
public bool IsStart { get; set; } = false;
|
||||
/// <summary>
|
||||
/// 执行传参
|
||||
/// </summary>
|
||||
public string JobParams { get; set; }
|
||||
|
||||
|
||||
[SugarColumn(IsNullable = true)]
|
||||
public bool? IsDeleted { get; set; }
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
[SugarColumn(IsNullable = true)]
|
||||
public DateTime CreateTime { get; set; } = DateTime.Now;
|
||||
}
|
||||
}
|
|
@ -86,6 +86,7 @@ namespace Blog.Core.Model.Models
|
|||
typeof(sysUserInfo),
|
||||
typeof(Topic),
|
||||
typeof(TopicDetail),
|
||||
typeof(TasksQz),
|
||||
typeof(UserRole));
|
||||
|
||||
// 后期单独处理某些表
|
||||
|
@ -214,6 +215,19 @@ namespace Blog.Core.Model.Models
|
|||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region TasksQz
|
||||
if (!await myContext.Db.Queryable<TasksQz>().AnyAsync())
|
||||
{
|
||||
myContext.GetEntityDB<TasksQz>().InsertRange(JsonHelper.ParseFormByJson<List<TasksQz>>(FileHelper.ReadFile(string.Format(SeedDataFolder, "TasksQz"), Encoding.UTF8)));
|
||||
Console.WriteLine("Table:TasksQz created success!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Table:TasksQz already exists...");
|
||||
}
|
||||
#endregion
|
||||
|
||||
Console.WriteLine("Done seeding database.");
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Blog.Core.IRepository\Blog.Core.IRepository.csproj" />
|
||||
<ProjectReference Include="..\Blog.Core.Model\Blog.Core.Model.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
19
Blog.Core.Repository/TasksQzRepository.cs
Normal file
19
Blog.Core.Repository/TasksQzRepository.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
|
||||
using Blog.Core.IRepository;
|
||||
using Blog.Core.IRepository.UnitOfWork;
|
||||
using Blog.Core.Model.Models;
|
||||
using Blog.Core.Repository.Base;
|
||||
|
||||
namespace Blog.Core.Repository
|
||||
{
|
||||
/// <summary>
|
||||
/// TasksQzRepository
|
||||
/// </summary>
|
||||
public class TasksQzRepository : BaseRepository<TasksQz>, ITasksQzRepository
|
||||
{
|
||||
public TasksQzRepository(IUnitOfWork unitOfWork) : base(unitOfWork)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,7 +16,6 @@
|
|||
<ItemGroup>
|
||||
<ProjectReference Include="..\Blog.Core.IRepository\Blog.Core.IRepository.csproj" />
|
||||
<ProjectReference Include="..\Blog.Core.IServices\Blog.Core.IServices.csproj" />
|
||||
<ProjectReference Include="..\Blog.Core.Model\Blog.Core.Model.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
20
Blog.Core.Services/TasksQzServices.cs
Normal file
20
Blog.Core.Services/TasksQzServices.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
|
||||
using Blog.Core.IRepository;
|
||||
using Blog.Core.IServices;
|
||||
using Blog.Core.Model.Models;
|
||||
using Blog.Core.Services.BASE;
|
||||
|
||||
namespace Blog.Core.Services
|
||||
{
|
||||
public partial class TasksQzServices : BaseServices<TasksQz>, ITasksQzServices
|
||||
{
|
||||
ITasksQzRepository _dal;
|
||||
public TasksQzServices(ITasksQzRepository dal)
|
||||
{
|
||||
this._dal = dal;
|
||||
base.BaseDal = dal;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,10 @@
|
|||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Quartz" Version="3.0.7" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Blog.Core.IServices\Blog.Core.IServices.csproj" />
|
||||
</ItemGroup>
|
||||
|
|
44
Blog.Core.Tasks/QuartzNet/ISchedulerCenter.cs
Normal file
44
Blog.Core.Tasks/QuartzNet/ISchedulerCenter.cs
Normal file
|
@ -0,0 +1,44 @@
|
|||
using Blog.Core.Model;
|
||||
using Blog.Core.Model.Models;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Blog.Core.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务调度接口
|
||||
/// </summary>
|
||||
public interface ISchedulerCenter
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 开启任务调度
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<MessageModel<string>> StartScheduleAsync();
|
||||
/// <summary>
|
||||
/// 停止任务调度
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<MessageModel<string>> StopScheduleAsync();
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="sysSchedule"></param>
|
||||
/// <returns></returns>
|
||||
Task<MessageModel<string>> AddScheduleJobAsync(TasksQz sysSchedule);
|
||||
/// <summary>
|
||||
/// 停止一个任务
|
||||
/// </summary>
|
||||
/// <param name="sysSchedule"></param>
|
||||
/// <returns></returns>
|
||||
Task<MessageModel<string>> StopScheduleJobAsync(TasksQz sysSchedule);
|
||||
/// <summary>
|
||||
/// 恢复一个任务
|
||||
/// </summary>
|
||||
/// <param name="sysSchedule"></param>
|
||||
/// <returns></returns>
|
||||
Task<MessageModel<string>> ResumeJob(TasksQz sysSchedule);
|
||||
|
||||
}
|
||||
|
||||
}
|
50
Blog.Core.Tasks/QuartzNet/JobFactory.cs
Normal file
50
Blog.Core.Tasks/QuartzNet/JobFactory.cs
Normal file
|
@ -0,0 +1,50 @@
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Quartz;
|
||||
using Quartz.Spi;
|
||||
using System;
|
||||
|
||||
namespace Blog.Core.Tasks
|
||||
{
|
||||
public class JobFactory : IJobFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// 注入反射获取依赖对象
|
||||
/// </summary>
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
public JobFactory(IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
/// <summary>
|
||||
/// 实现接口Job
|
||||
/// </summary>
|
||||
/// <param name="bundle"></param>
|
||||
/// <param name="scheduler"></param>
|
||||
/// <returns></returns>
|
||||
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
|
||||
{
|
||||
try
|
||||
{
|
||||
var serviceScope = _serviceProvider.CreateScope();
|
||||
var job = serviceScope.ServiceProvider.GetService(bundle.JobDetail.JobType) as IJob;
|
||||
return job;
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public void ReturnJob(IJob job)
|
||||
{
|
||||
var disposable = job as IDisposable;
|
||||
if (disposable != null)
|
||||
{
|
||||
disposable.Dispose();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
45
Blog.Core.Tasks/QuartzNet/Jobs/JobBase.cs
Normal file
45
Blog.Core.Tasks/QuartzNet/Jobs/JobBase.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
using Blog.Core.Common.LogHelper;
|
||||
using Quartz;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Blog.Core.Tasks
|
||||
{
|
||||
public class JobBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 执行指定任务
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="action"></param>
|
||||
public async Task<string> ExecuteJob(IJobExecutionContext context, Func<Task> func)
|
||||
{
|
||||
string jobHistory = $"【{DateTime.Now}】执行任务【Id:{context.JobDetail.Key.Name},组别:{context.JobDetail.Key.Group}】";
|
||||
try
|
||||
{
|
||||
var s = context.Trigger.Key.Name;
|
||||
//记录Job时间
|
||||
Stopwatch stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
await func();//执行任务
|
||||
stopwatch.Stop();
|
||||
jobHistory += $",【执行成功】,完成时间:{stopwatch.Elapsed.TotalMilliseconds.ToString("00")}毫秒";
|
||||
//SerilogServer.WriteLog(context.Trigger.Key.Name.Replace("-", ""), $"{context.Trigger.Key.Name}定时任务运行一切OK", "任务结束");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
JobExecutionException e2 = new JobExecutionException(ex);
|
||||
//true 是立即重新执行任务
|
||||
e2.RefireImmediately = true;
|
||||
//SerilogServer.WriteErrorLog(context.Trigger.Key.Name.Replace("-", ""), $"{context.Trigger.Key.Name}任务运行异常", ex);
|
||||
|
||||
jobHistory += $",【执行失败】,异常日志:{ex.Message}";
|
||||
}
|
||||
|
||||
Console.Out.WriteLine(jobHistory);
|
||||
return jobHistory;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
52
Blog.Core.Tasks/QuartzNet/Jobs/Job_Blogs_Quartz.cs
Normal file
52
Blog.Core.Tasks/QuartzNet/Jobs/Job_Blogs_Quartz.cs
Normal file
|
@ -0,0 +1,52 @@
|
|||
using Blog.Core.IServices;
|
||||
using Quartz;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
/// <summary>
|
||||
/// 这里要注意下,命名空间和程序集是一样的,不然反射不到
|
||||
/// </summary>
|
||||
namespace Blog.Core.Tasks
|
||||
{
|
||||
public class Job_Blogs_Quartz : JobBase, IJob
|
||||
{
|
||||
private readonly IBlogArticleServices _blogArticleServices;
|
||||
private readonly ITasksQzServices _tasksQzServices;
|
||||
|
||||
public Job_Blogs_Quartz(IBlogArticleServices blogArticleServices, ITasksQzServices tasksQzServices)
|
||||
{
|
||||
_blogArticleServices = blogArticleServices;
|
||||
_tasksQzServices = tasksQzServices;
|
||||
}
|
||||
public async Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
var executeLog = await ExecuteJob(context, async () => await Run(context));
|
||||
|
||||
//var param = context.MergedJobDataMap;
|
||||
// 可以直接获取 JobDetail 的值
|
||||
var jobKey = context.JobDetail.Key;
|
||||
var jobId = jobKey.Name;
|
||||
|
||||
// 也可以通过数据库配置,获取传递过来的参数
|
||||
JobDataMap data = context.JobDetail.JobDataMap;
|
||||
//int jobId = data.GetInt("JobParam");
|
||||
|
||||
var model = await _tasksQzServices.QueryById(jobId);
|
||||
if (model != null)
|
||||
{
|
||||
model.RunTimes += 1;
|
||||
model.Remark += $"{executeLog}<br />";
|
||||
await _tasksQzServices.Update(model);
|
||||
}
|
||||
|
||||
}
|
||||
public async Task Run(IJobExecutionContext context)
|
||||
{
|
||||
var list = await _blogArticleServices.Query();
|
||||
await Console.Out.WriteLineAsync("博客总数量" + list.Count.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
305
Blog.Core.Tasks/QuartzNet/SchedulerCenterServer.cs
Normal file
305
Blog.Core.Tasks/QuartzNet/SchedulerCenterServer.cs
Normal file
|
@ -0,0 +1,305 @@
|
|||
using Blog.Core.Model;
|
||||
using Blog.Core.Model.Models;
|
||||
using Quartz;
|
||||
using Quartz.Impl;
|
||||
using Quartz.Spi;
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Blog.Core.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// 任务调度管理中心
|
||||
/// </summary>
|
||||
public class SchedulerCenterServer : ISchedulerCenter
|
||||
{
|
||||
private Task<IScheduler> _scheduler;
|
||||
private readonly IJobFactory _iocjobFactory;
|
||||
public SchedulerCenterServer(IJobFactory jobFactory)
|
||||
{
|
||||
_iocjobFactory = jobFactory;
|
||||
_scheduler = GetSchedulerAsync();
|
||||
}
|
||||
private Task<IScheduler> GetSchedulerAsync()
|
||||
{
|
||||
if (_scheduler != null)
|
||||
return this._scheduler;
|
||||
else
|
||||
{
|
||||
// 从Factory中获取Scheduler实例
|
||||
NameValueCollection collection = new NameValueCollection
|
||||
{
|
||||
{ "quartz.serializer.type", "binary" },
|
||||
};
|
||||
StdSchedulerFactory factory = new StdSchedulerFactory(collection);
|
||||
return _scheduler = factory.GetScheduler();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开启任务调度
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<MessageModel<string>> StartScheduleAsync()
|
||||
{
|
||||
var result = new MessageModel<string>();
|
||||
try
|
||||
{
|
||||
this._scheduler.Result.JobFactory = this._iocjobFactory;
|
||||
if (!this._scheduler.Result.IsStarted)
|
||||
{
|
||||
//等待任务运行完成
|
||||
await this._scheduler.Result.Start();
|
||||
await Console.Out.WriteLineAsync("任务调度开启!");
|
||||
result.success = true;
|
||||
result.msg = $"任务调度开启成功";
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.success = false;
|
||||
result.msg = $"任务调度已经开启";
|
||||
return result;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止任务调度
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<MessageModel<string>> StopScheduleAsync()
|
||||
{
|
||||
var result = new MessageModel<string>();
|
||||
try
|
||||
{
|
||||
if (!this._scheduler.Result.IsShutdown)
|
||||
{
|
||||
//等待任务运行完成
|
||||
await this._scheduler.Result.Shutdown();
|
||||
await Console.Out.WriteLineAsync("任务调度停止!");
|
||||
result.success = true;
|
||||
result.msg = $"任务调度停止成功";
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.success = false;
|
||||
result.msg = $"任务调度已经停止";
|
||||
return result;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个计划任务(映射程序集指定IJob实现类)
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="tasksQz"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<MessageModel<string>> AddScheduleJobAsync(TasksQz tasksQz)
|
||||
{
|
||||
var result = new MessageModel<string>();
|
||||
try
|
||||
{
|
||||
if (tasksQz != null)
|
||||
{
|
||||
JobKey jobKey = new JobKey(tasksQz.Id.ToString(), tasksQz.JobGroup);
|
||||
if (await _scheduler.Result.CheckExists(jobKey))
|
||||
{
|
||||
result.success = false;
|
||||
result.msg = $"该任务计划已经在执行:【{tasksQz.Name}】,请勿重复启动!";
|
||||
return result;
|
||||
}
|
||||
#region 设置开始时间和结束时间
|
||||
|
||||
if (tasksQz.BeginTime == null)
|
||||
{
|
||||
tasksQz.BeginTime = DateTime.Now;
|
||||
}
|
||||
DateTimeOffset starRunTime = DateBuilder.NextGivenSecondDate(tasksQz.BeginTime, 1);//设置开始时间
|
||||
if (tasksQz.EndTime == null)
|
||||
{
|
||||
tasksQz.EndTime = DateTime.MaxValue.AddDays(-1);
|
||||
}
|
||||
DateTimeOffset endRunTime = DateBuilder.NextGivenSecondDate(tasksQz.EndTime, 1);//设置暂停时间
|
||||
|
||||
#endregion
|
||||
|
||||
#region 通过反射获取程序集类型和类
|
||||
|
||||
Assembly assembly = Assembly.Load(new AssemblyName(tasksQz.AssemblyName));
|
||||
Type jobType = assembly.GetType(tasksQz.AssemblyName + "." + tasksQz.ClassName);
|
||||
|
||||
#endregion
|
||||
//判断任务调度是否开启
|
||||
if (!_scheduler.Result.IsStarted)
|
||||
{
|
||||
await StartScheduleAsync();
|
||||
}
|
||||
|
||||
//传入反射出来的执行程序集
|
||||
IJobDetail job = new JobDetailImpl(tasksQz.Id.ToString(), tasksQz.JobGroup, jobType);
|
||||
job.JobDataMap.Add("JobParam", tasksQz.JobParams);
|
||||
ITrigger trigger;
|
||||
|
||||
#region 泛型传递
|
||||
//IJobDetail job = JobBuilder.Create<T>()
|
||||
// .WithIdentity(sysSchedule.Name, sysSchedule.JobGroup)
|
||||
// .Build();
|
||||
#endregion
|
||||
|
||||
if (tasksQz.Cron != null && CronExpression.IsValidExpression(tasksQz.Cron) && tasksQz.TriggerType > 0)
|
||||
{
|
||||
trigger = CreateCronTrigger(tasksQz);
|
||||
}
|
||||
else
|
||||
{
|
||||
trigger = CreateSimpleTrigger(tasksQz);
|
||||
}
|
||||
// 告诉Quartz使用我们的触发器来安排作业
|
||||
await _scheduler.Result.ScheduleJob(job, trigger);
|
||||
//await Task.Delay(TimeSpan.FromSeconds(120));
|
||||
//await Console.Out.WriteLineAsync("关闭了调度器!");
|
||||
//await _scheduler.Result.Shutdown();
|
||||
result.success = true;
|
||||
result.msg = $"启动任务:【{tasksQz.Name}】成功";
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.success = false;
|
||||
result.msg = $"任务计划不存在:【{tasksQz.Name}】";
|
||||
return result;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 暂停一个指定的计划任务
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<MessageModel<string>> StopScheduleJobAsync(TasksQz sysSchedule)
|
||||
{
|
||||
var result = new MessageModel<string>();
|
||||
try
|
||||
{
|
||||
JobKey jobKey = new JobKey(sysSchedule.Id.ToString(), sysSchedule.JobGroup);
|
||||
if (!await _scheduler.Result.CheckExists(jobKey))
|
||||
{
|
||||
result.success = false;
|
||||
result.msg = $"未找到要暂停的任务:【{sysSchedule.Name}】";
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
await this._scheduler.Result.PauseJob(jobKey);
|
||||
result.success = true;
|
||||
result.msg = $"暂停任务:【{sysSchedule.Name}】成功";
|
||||
return result;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 恢复指定的计划任务
|
||||
/// </summary>
|
||||
/// <param name="sysSchedule"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<MessageModel<string>> ResumeJob(TasksQz sysSchedule)
|
||||
{
|
||||
var result = new MessageModel<string>();
|
||||
try
|
||||
{
|
||||
JobKey jobKey = new JobKey(sysSchedule.Id.ToString(), sysSchedule.JobGroup);
|
||||
if (!await _scheduler.Result.CheckExists(jobKey))
|
||||
{
|
||||
result.success = false;
|
||||
result.msg = $"未找到要重新的任务:【{sysSchedule.Name}】,请先选择添加计划!";
|
||||
return result;
|
||||
}
|
||||
await this._scheduler.Result.ResumeJob(jobKey);
|
||||
result.success = true;
|
||||
result.msg = $"恢复计划任务:【{sysSchedule.Name}】成功";
|
||||
return result;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#region 创建触发器帮助方法
|
||||
|
||||
/// <summary>
|
||||
/// 创建SimpleTrigger触发器(简单触发器)
|
||||
/// </summary>
|
||||
/// <param name="sysSchedule"></param>
|
||||
/// <param name="starRunTime"></param>
|
||||
/// <param name="endRunTime"></param>
|
||||
/// <returns></returns>
|
||||
private ITrigger CreateSimpleTrigger(TasksQz sysSchedule)
|
||||
{
|
||||
if (sysSchedule.RunTimes > 0)
|
||||
{
|
||||
ITrigger trigger = TriggerBuilder.Create()
|
||||
.WithIdentity(sysSchedule.Id.ToString(), sysSchedule.JobGroup)
|
||||
.StartAt(sysSchedule.BeginTime.Value)
|
||||
.EndAt(sysSchedule.EndTime.Value)
|
||||
.WithSimpleSchedule(x =>
|
||||
x.WithIntervalInSeconds(sysSchedule.IntervalSecond)
|
||||
.WithRepeatCount(sysSchedule.RunTimes)).ForJob(sysSchedule.Id.ToString(), sysSchedule.JobGroup).Build();
|
||||
return trigger;
|
||||
}
|
||||
else
|
||||
{
|
||||
ITrigger trigger = TriggerBuilder.Create()
|
||||
.WithIdentity(sysSchedule.Id.ToString(), sysSchedule.JobGroup)
|
||||
.StartAt(sysSchedule.BeginTime.Value)
|
||||
.EndAt(sysSchedule.EndTime.Value)
|
||||
.WithSimpleSchedule(x =>
|
||||
x.WithIntervalInSeconds(sysSchedule.IntervalSecond)
|
||||
.RepeatForever()).ForJob(sysSchedule.Id.ToString(), sysSchedule.JobGroup).Build();
|
||||
return trigger;
|
||||
}
|
||||
// 触发作业立即运行,然后每10秒重复一次,无限循环
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 创建类型Cron的触发器
|
||||
/// </summary>
|
||||
/// <param name="m"></param>
|
||||
/// <returns></returns>
|
||||
private ITrigger CreateCronTrigger(TasksQz sysSchedule)
|
||||
{
|
||||
// 作业触发器
|
||||
return TriggerBuilder.Create()
|
||||
.WithIdentity(sysSchedule.Id.ToString(), sysSchedule.JobGroup)
|
||||
.StartAt(sysSchedule.BeginTime.Value)//开始时间
|
||||
.EndAt(sysSchedule.EndTime.Value)//结束数据
|
||||
.WithCronSchedule(sysSchedule.Cron)//指定cron表达式
|
||||
.ForJob(sysSchedule.Id.ToString(), sysSchedule.JobGroup)//作业名称
|
||||
.Build();
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
|
@ -53,8 +53,9 @@ namespace Blog.Core.AuthHelper
|
|||
select new PermissionItem
|
||||
{
|
||||
Url = item.Module?.LinkUrl,
|
||||
Role = item.Role?.Id.ObjToString(),
|
||||
Role = item.Role?.Name,
|
||||
}).ToList();
|
||||
|
||||
requirement.Permissions = list;
|
||||
}
|
||||
|
||||
|
|
|
@ -655,6 +655,81 @@
|
|||
登录账号
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Blog.Core.Model.Models.TasksQz">
|
||||
<summary>
|
||||
任务计划表
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Blog.Core.Model.Models.TasksQz.Name">
|
||||
<summary>
|
||||
任务名称
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Blog.Core.Model.Models.TasksQz.JobGroup">
|
||||
<summary>
|
||||
任务分组
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Blog.Core.Model.Models.TasksQz.Cron">
|
||||
<summary>
|
||||
任务运行时间表达式
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Blog.Core.Model.Models.TasksQz.AssemblyName">
|
||||
<summary>
|
||||
任务所在DLL对应的程序集名称
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Blog.Core.Model.Models.TasksQz.ClassName">
|
||||
<summary>
|
||||
任务所在类
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Blog.Core.Model.Models.TasksQz.Remark">
|
||||
<summary>
|
||||
任务描述
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Blog.Core.Model.Models.TasksQz.RunTimes">
|
||||
<summary>
|
||||
执行次数
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Blog.Core.Model.Models.TasksQz.BeginTime">
|
||||
<summary>
|
||||
开始时间
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Blog.Core.Model.Models.TasksQz.EndTime">
|
||||
<summary>
|
||||
结束时间
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Blog.Core.Model.Models.TasksQz.TriggerType">
|
||||
<summary>
|
||||
触发器类型(0、simple 1、cron)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Blog.Core.Model.Models.TasksQz.IntervalSecond">
|
||||
<summary>
|
||||
执行间隔时间, 秒为单位
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Blog.Core.Model.Models.TasksQz.IsStart">
|
||||
<summary>
|
||||
是否启动
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Blog.Core.Model.Models.TasksQz.JobParams">
|
||||
<summary>
|
||||
执行传参
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Blog.Core.Model.Models.TasksQz.CreateTime">
|
||||
<summary>
|
||||
创建时间
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Blog.Core.Model.Models.Topic">
|
||||
<summary>
|
||||
Tibug 类别
|
||||
|
|
|
@ -597,6 +597,49 @@
|
|||
<param name="id"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:Blog.Core.Controllers.TasksQzController.Get(System.Int32,System.String)">
|
||||
<summary>
|
||||
分页获取
|
||||
</summary>
|
||||
<param name="page"></param>
|
||||
<param name="key"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:Blog.Core.Controllers.TasksQzController.Post(Blog.Core.Model.Models.TasksQz)">
|
||||
<summary>
|
||||
添加计划任务
|
||||
</summary>
|
||||
<param name="tasksQz"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:Blog.Core.Controllers.TasksQzController.Put(Blog.Core.Model.Models.TasksQz)">
|
||||
<summary>
|
||||
修改计划任务
|
||||
</summary>
|
||||
<param name="tasksQz"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:Blog.Core.Controllers.TasksQzController.StartJob(System.Int32)">
|
||||
<summary>
|
||||
启动计划任务
|
||||
</summary>
|
||||
<param name="jobId"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:Blog.Core.Controllers.TasksQzController.StopJob(System.Int32)">
|
||||
<summary>
|
||||
停止一个计划任务
|
||||
</summary>
|
||||
<param name="jobId"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:Blog.Core.Controllers.TasksQzController.ReCovery(System.Guid)">
|
||||
<summary>
|
||||
重启一个计划任务
|
||||
</summary>
|
||||
<param name="jobId"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:Blog.Core.Controllers.TopicController">
|
||||
<summary>
|
||||
类别管理【无权限】
|
||||
|
|
174
Blog.Core/Controllers/TasksQzController.cs
Normal file
174
Blog.Core/Controllers/TasksQzController.cs
Normal file
|
@ -0,0 +1,174 @@
|
|||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading.Tasks;
|
||||
using Blog.Core.IServices;
|
||||
using Blog.Core.Model;
|
||||
using Blog.Core.Model.Models;
|
||||
using Blog.Core.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Blog.Core.Controllers
|
||||
{
|
||||
[Route("api/[controller]/[action]")]
|
||||
[ApiController]
|
||||
public class TasksQzController : ControllerBase
|
||||
{
|
||||
private readonly ITasksQzServices _tasksQzServices;
|
||||
private readonly ISchedulerCenter _schedulerCenter;
|
||||
|
||||
public TasksQzController(ITasksQzServices tasksQzServices, ISchedulerCenter schedulerCenter)
|
||||
{
|
||||
_tasksQzServices = tasksQzServices;
|
||||
_schedulerCenter = schedulerCenter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分页获取
|
||||
/// </summary>
|
||||
/// <param name="page"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
// GET: api/Buttons/5
|
||||
[HttpGet]
|
||||
public async Task<MessageModel<PageModel<TasksQz>>> Get(int page = 1, string key = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(key) || string.IsNullOrWhiteSpace(key))
|
||||
{
|
||||
key = "";
|
||||
}
|
||||
int intPageSize = 50;
|
||||
|
||||
Expression<Func<TasksQz, bool>> whereExpression = a => a.IsDeleted != true && (a.Name != null && a.Name.Contains(key));
|
||||
|
||||
var data = await _tasksQzServices.QueryPage(whereExpression, page, intPageSize, " Id desc ");
|
||||
|
||||
return new MessageModel<PageModel<TasksQz>>()
|
||||
{
|
||||
msg = "获取成功",
|
||||
success = data.dataCount >= 0,
|
||||
response = data
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加计划任务
|
||||
/// </summary>
|
||||
/// <param name="tasksQz"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<MessageModel<string>> Post([FromBody] TasksQz tasksQz)
|
||||
{
|
||||
var data = new MessageModel<string>();
|
||||
|
||||
var id = (await _tasksQzServices.Add(tasksQz));
|
||||
data.success = id > 0;
|
||||
if (data.success)
|
||||
{
|
||||
data.response = id.ObjToString();
|
||||
data.msg = "添加成功";
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 修改计划任务
|
||||
/// </summary>
|
||||
/// <param name="tasksQz"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPut]
|
||||
public async Task<MessageModel<string>> Put([FromBody] TasksQz tasksQz)
|
||||
{
|
||||
var data = new MessageModel<string>();
|
||||
if (tasksQz != null && tasksQz.Id > 0)
|
||||
{
|
||||
data.success = await _tasksQzServices.Update(tasksQz);
|
||||
if (data.success)
|
||||
{
|
||||
data.msg = "更新成功";
|
||||
data.response = tasksQz?.Id.ObjToString();
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动计划任务
|
||||
/// </summary>
|
||||
/// <param name="jobId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public async Task<MessageModel<string>> StartJob(int jobId)
|
||||
{
|
||||
var data = new MessageModel<string>();
|
||||
|
||||
var model = await _tasksQzServices.QueryById(jobId);
|
||||
var ResuleModel = await _schedulerCenter.AddScheduleJobAsync(model);
|
||||
if (ResuleModel.success)
|
||||
{
|
||||
model.IsStart = true;
|
||||
data.success = await _tasksQzServices.Update(model);
|
||||
}
|
||||
if (data.success)
|
||||
{
|
||||
data.msg = "启动成功";
|
||||
data.response = jobId.ObjToString();
|
||||
}
|
||||
return data;
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 停止一个计划任务
|
||||
/// </summary>
|
||||
/// <param name="jobId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public async Task<MessageModel<string>> StopJob(int jobId)
|
||||
{
|
||||
var data = new MessageModel<string>();
|
||||
|
||||
var model = await _tasksQzServices.QueryById(jobId);
|
||||
var ResuleModel = await _schedulerCenter.StopScheduleJobAsync(model);
|
||||
if (ResuleModel.success)
|
||||
{
|
||||
model.IsStart = false;
|
||||
data.success = await _tasksQzServices.Update(model);
|
||||
}
|
||||
if (data.success)
|
||||
{
|
||||
data.msg = "暂停成功";
|
||||
data.response = jobId.ObjToString();
|
||||
}
|
||||
return data;
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 重启一个计划任务
|
||||
/// </summary>
|
||||
/// <param name="jobId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public async Task<MessageModel<string>> ReCovery(Guid jobId)
|
||||
{
|
||||
var data = new MessageModel<string>();
|
||||
|
||||
var model = await _tasksQzServices.QueryById(jobId);
|
||||
var ResuleModel = await _schedulerCenter.ResumeJob(model);
|
||||
if (ResuleModel.success)
|
||||
{
|
||||
model.IsStart = true;
|
||||
data.success = await _tasksQzServices.Update(model);
|
||||
}
|
||||
if (data.success)
|
||||
{
|
||||
data.msg = "重启成功";
|
||||
data.response = jobId.ObjToString();
|
||||
}
|
||||
return data;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
using Blog.Core.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Quartz.Spi;
|
||||
using System;
|
||||
|
||||
namespace Blog.Core.Extensions
|
||||
|
@ -15,6 +16,10 @@ namespace Blog.Core.Extensions
|
|||
|
||||
services.AddHostedService<Job1TimedService>();
|
||||
services.AddHostedService<Job2TimedService>();
|
||||
|
||||
services.AddSingleton<IJobFactory, JobFactory>();
|
||||
services.AddTransient<Job_Blogs_Quartz>();//Job使用瞬时依赖注入
|
||||
services.AddSingleton<ISchedulerCenter, SchedulerCenterServer>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
20
Blog.Core/wwwroot/BlogCore.Data.json/TasksQz.tsv
Normal file
20
Blog.Core/wwwroot/BlogCore.Data.json/TasksQz.tsv
Normal file
|
@ -0,0 +1,20 @@
|
|||
[
|
||||
{
|
||||
"Name": "博客管理",
|
||||
"JobGroup": "博客测试组",
|
||||
"Cron": "",
|
||||
"AssemblyName": "Blog.Core.Tasks",
|
||||
"ClassName": "Job_Blogs_Quartz",
|
||||
"Remark": "",
|
||||
"RunTimes": 0,
|
||||
"BeginTime": "\/Date(1546272000000+0800)\/",
|
||||
"EndTime": "\/Date(1546272000000+0800)\/",
|
||||
"TriggerType": 0,
|
||||
"IntervalSecond": 120,
|
||||
"IsStart": true,
|
||||
"JobParams": "1",
|
||||
"IsDeleted": false,
|
||||
"CreateTime": "\/Date(1546272000000+0800)\/",
|
||||
"Id": 1
|
||||
}
|
||||
]
|
Can't render this file because it contains an unexpected character in line 3 and column 5.
|
Loading…
Reference in New Issue
Block a user