2024-01-12 17:18:39 +08:00
|
|
|
|
using System.Reflection;
|
|
|
|
|
|
using Mapster;
|
|
|
|
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
|
|
using Quartz;
|
|
|
|
|
|
using Quartz.Impl.Matchers;
|
2024-01-13 16:17:48 +08:00
|
|
|
|
using Volo.Abp;
|
2024-01-12 17:18:39 +08:00
|
|
|
|
using Volo.Abp.Application.Dtos;
|
|
|
|
|
|
using Volo.Abp.Application.Services;
|
2024-01-13 16:17:48 +08:00
|
|
|
|
using Volo.Abp.Timing;
|
2024-01-12 17:18:39 +08:00
|
|
|
|
using Yi.Framework.Rbac.Application.Contracts.Dtos.Task;
|
2023-12-11 09:55:12 +08:00
|
|
|
|
using Yi.Framework.Rbac.Application.Contracts.IServices;
|
2024-01-12 17:18:39 +08:00
|
|
|
|
using Yi.Framework.Rbac.Domain.Shared.Enums;
|
2023-12-11 09:55:12 +08:00
|
|
|
|
|
2024-02-18 09:35:35 +08:00
|
|
|
|
namespace Yi.Framework.Rbac.Application.Services.Monitor
|
2023-12-11 09:55:12 +08:00
|
|
|
|
{
|
|
|
|
|
|
public class TaskService : ApplicationService, ITaskService
|
|
|
|
|
|
{
|
2024-01-12 17:18:39 +08:00
|
|
|
|
private readonly ISchedulerFactory _schedulerFactory;
|
2024-01-13 16:17:48 +08:00
|
|
|
|
private readonly IClock _clock;
|
|
|
|
|
|
public TaskService(ISchedulerFactory schedulerFactory, IClock clock)
|
2024-01-12 17:18:39 +08:00
|
|
|
|
{
|
2024-02-18 09:35:35 +08:00
|
|
|
|
_clock = clock;
|
2024-01-12 17:18:39 +08:00
|
|
|
|
_schedulerFactory = schedulerFactory;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 单查job
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="jobId"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2024-01-13 16:17:48 +08:00
|
|
|
|
[HttpGet("task/{jobId}")]
|
|
|
|
|
|
public async Task<TaskGetOutput> GetAsync([FromRoute] string jobId)
|
2024-01-12 17:18:39 +08:00
|
|
|
|
{
|
|
|
|
|
|
var scheduler = await _schedulerFactory.GetScheduler();
|
|
|
|
|
|
|
|
|
|
|
|
var jobDetail = await scheduler.GetJobDetail(new JobKey(jobId));
|
|
|
|
|
|
var trigger = (await scheduler.GetTriggersOfJob(new JobKey(jobId))).First();
|
|
|
|
|
|
//状态
|
|
|
|
|
|
var state = await scheduler.GetTriggerState(trigger.Key);
|
2024-01-13 16:17:48 +08:00
|
|
|
|
|
2024-02-18 09:35:35 +08:00
|
|
|
|
|
2024-01-12 17:18:39 +08:00
|
|
|
|
var output = new TaskGetOutput
|
|
|
|
|
|
{
|
|
|
|
|
|
JobId = jobDetail.Key.Name,
|
|
|
|
|
|
GroupName = jobDetail.Key.Group,
|
|
|
|
|
|
JobType = jobDetail.JobType.Name,
|
|
|
|
|
|
Properties = Newtonsoft.Json.JsonConvert.SerializeObject(jobDetail.JobDataMap),
|
|
|
|
|
|
Concurrent = !jobDetail.ConcurrentExecutionDisallowed,
|
|
|
|
|
|
Description = jobDetail.Description,
|
2024-02-18 09:35:35 +08:00
|
|
|
|
LastRunTime = _clock.Normalize(trigger.GetPreviousFireTimeUtc()?.DateTime ?? DateTime.MinValue),
|
2024-01-13 16:17:48 +08:00
|
|
|
|
NextRunTime = _clock.Normalize(trigger.GetNextFireTimeUtc()?.DateTime ?? DateTime.MinValue),
|
|
|
|
|
|
AssemblyName = jobDetail.JobType.Assembly.GetName().Name,
|
|
|
|
|
|
Status = state.ToString()
|
2024-01-12 17:18:39 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
if (trigger is ISimpleTrigger simple)
|
|
|
|
|
|
{
|
2024-02-18 09:35:35 +08:00
|
|
|
|
output.TriggerArgs = Math.Round(simple.RepeatInterval.TotalMinutes, 2).ToString() + "分钟";
|
2024-01-13 16:17:48 +08:00
|
|
|
|
output.Type = JobTypeEnum.Millisecond;
|
2024-01-13 16:44:39 +08:00
|
|
|
|
output.Millisecond = simple.RepeatInterval.TotalMilliseconds;
|
2024-01-12 17:18:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
else if (trigger is ICronTrigger cron)
|
|
|
|
|
|
{
|
|
|
|
|
|
output.TriggerArgs = cron.CronExpressionString!;
|
2024-01-13 16:17:48 +08:00
|
|
|
|
output.Type = JobTypeEnum.Cron;
|
2024-02-18 09:35:35 +08:00
|
|
|
|
output.Cron = cron.CronExpressionString;
|
2024-01-12 17:18:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
return output;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 多查job
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
2024-01-13 16:17:48 +08:00
|
|
|
|
public async Task<PagedResultDto<TaskGetListOutput>> GetListAsync([FromQuery] TaskGetListInput input)
|
2024-01-12 17:18:39 +08:00
|
|
|
|
{
|
|
|
|
|
|
var items = new List<TaskGetOutput>();
|
|
|
|
|
|
|
|
|
|
|
|
var scheduler = await _schedulerFactory.GetScheduler();
|
|
|
|
|
|
|
|
|
|
|
|
var groups = await scheduler.GetJobGroupNames();
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var groupName in groups)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var jobKey in await scheduler.GetJobKeys(GroupMatcher<JobKey>.GroupEquals(groupName)))
|
|
|
|
|
|
{
|
|
|
|
|
|
string jobName = jobKey.Name;
|
|
|
|
|
|
string jobGroup = jobKey.Group;
|
|
|
|
|
|
var triggers = (await scheduler.GetTriggersOfJob(jobKey)).First();
|
2024-01-13 16:17:48 +08:00
|
|
|
|
items.Add(await GetAsync(jobName));
|
2024-01-12 17:18:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var output = items.Skip((input.SkipCount - 1) * input.MaxResultCount).Take(input.MaxResultCount)
|
|
|
|
|
|
.OrderByDescending(x => x.LastRunTime)
|
|
|
|
|
|
.ToList();
|
|
|
|
|
|
return new PagedResultDto<TaskGetListOutput>(items.Count(), output.Adapt<List<TaskGetListOutput>>());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 创建job
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="input"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2024-01-13 16:17:48 +08:00
|
|
|
|
public async Task CreateAsync(TaskCreateInput input)
|
2024-01-12 17:18:39 +08:00
|
|
|
|
{
|
|
|
|
|
|
var scheduler = await _schedulerFactory.GetScheduler();
|
|
|
|
|
|
|
|
|
|
|
|
//设置启动时执行一次,然后最大只执行一次
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//jobBuilder
|
2024-01-13 16:17:48 +08:00
|
|
|
|
var jobClassType = Assembly.Load(input.AssemblyName).GetTypes().Where(x => x.Name == input.JobType).FirstOrDefault();
|
|
|
|
|
|
|
|
|
|
|
|
if (jobClassType is null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new UserFriendlyException($"程序集:{input.AssemblyName},{input.JobType} 不存在");
|
|
|
|
|
|
}
|
2024-01-12 17:18:39 +08:00
|
|
|
|
|
|
|
|
|
|
var jobBuilder = JobBuilder.Create(jobClassType).WithIdentity(new JobKey(input.JobId, input.GroupName))
|
|
|
|
|
|
.WithDescription(input.Description);
|
|
|
|
|
|
if (!input.Concurrent)
|
|
|
|
|
|
{
|
|
|
|
|
|
jobBuilder.DisallowConcurrentExecution();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//triggerBuilder
|
|
|
|
|
|
TriggerBuilder triggerBuilder = null;
|
|
|
|
|
|
switch (input.Type)
|
|
|
|
|
|
{
|
|
|
|
|
|
case JobTypeEnum.Cron:
|
2024-01-13 16:17:48 +08:00
|
|
|
|
triggerBuilder =
|
|
|
|
|
|
TriggerBuilder.Create()
|
2024-01-12 17:18:39 +08:00
|
|
|
|
.WithCronSchedule(input.Cron);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
case JobTypeEnum.Millisecond:
|
|
|
|
|
|
triggerBuilder =
|
|
|
|
|
|
TriggerBuilder.Create().StartNow()
|
|
|
|
|
|
.WithSimpleSchedule(x => x
|
2024-01-13 16:17:48 +08:00
|
|
|
|
.WithInterval(TimeSpan.FromMilliseconds(input.Millisecond ?? 10000))
|
2024-01-12 17:18:39 +08:00
|
|
|
|
.RepeatForever()
|
|
|
|
|
|
);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//作业计划,单个jobBuilder与多个triggerBuilder组合
|
|
|
|
|
|
await scheduler.ScheduleJob(jobBuilder.Build(), triggerBuilder.Build());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 移除job
|
|
|
|
|
|
/// </summary>
|
2024-01-13 16:17:48 +08:00
|
|
|
|
/// <param name="id"></param>
|
2024-01-12 17:18:39 +08:00
|
|
|
|
/// <returns></returns>
|
2024-01-13 16:17:48 +08:00
|
|
|
|
public async Task DeleteAsync(IEnumerable<string> id)
|
2024-02-18 09:35:35 +08:00
|
|
|
|
{
|
2024-01-12 17:18:39 +08:00
|
|
|
|
var scheduler = await _schedulerFactory.GetScheduler();
|
2024-01-13 16:17:48 +08:00
|
|
|
|
await scheduler.DeleteJobs(id.Select(x => new JobKey(x)).ToList());
|
2024-01-12 17:18:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 暂停job
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="jobId"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
[HttpPut]
|
2024-01-13 16:17:48 +08:00
|
|
|
|
public async Task PauseAsync(string jobId)
|
2024-01-12 17:18:39 +08:00
|
|
|
|
{
|
|
|
|
|
|
var scheduler = await _schedulerFactory.GetScheduler();
|
|
|
|
|
|
await scheduler.PauseJob(new JobKey(jobId));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 开始job
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="jobId"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
[HttpPut]
|
2024-01-13 16:17:48 +08:00
|
|
|
|
public async Task StartAsync(string jobId)
|
2024-01-12 17:18:39 +08:00
|
|
|
|
{
|
|
|
|
|
|
var scheduler = await _schedulerFactory.GetScheduler();
|
|
|
|
|
|
await scheduler.ResumeJob(new JobKey(jobId));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 更新job
|
|
|
|
|
|
/// </summary>
|
2024-01-13 16:17:48 +08:00
|
|
|
|
/// <param name="id"></param>
|
2024-01-12 17:18:39 +08:00
|
|
|
|
/// <param name="input"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2024-01-13 16:17:48 +08:00
|
|
|
|
public async Task UpdateAsync(string id, TaskUpdateInput input)
|
2024-01-12 17:18:39 +08:00
|
|
|
|
{
|
2024-01-13 16:17:48 +08:00
|
|
|
|
await DeleteAsync(new List<string>() { id });
|
|
|
|
|
|
await CreateAsync(input.Adapt<TaskCreateInput>());
|
2024-01-12 17:18:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-01-13 16:17:48 +08:00
|
|
|
|
[HttpPost("task/run-once/{id}")]
|
|
|
|
|
|
public async Task RunOnceAsync([FromRoute] string id)
|
2024-01-12 17:18:39 +08:00
|
|
|
|
{
|
|
|
|
|
|
var scheduler = await _schedulerFactory.GetScheduler();
|
2024-01-13 16:17:48 +08:00
|
|
|
|
var jobDetail = await scheduler.GetJobDetail(new JobKey(id));
|
2024-01-12 17:18:39 +08:00
|
|
|
|
|
2024-01-13 16:17:48 +08:00
|
|
|
|
var jobBuilder = JobBuilder.Create(jobDetail.JobType).WithIdentity(new JobKey(Guid.NewGuid().ToString()));
|
2024-01-12 17:18:39 +08:00
|
|
|
|
//设置启动时执行一次,然后最大只执行一次
|
|
|
|
|
|
var trigger = TriggerBuilder.Create().WithIdentity(Guid.NewGuid().ToString()).StartNow()
|
|
|
|
|
|
.WithSimpleSchedule(x => x
|
2024-01-13 16:17:48 +08:00
|
|
|
|
.WithIntervalInHours(1)
|
2024-01-12 17:18:39 +08:00
|
|
|
|
.WithRepeatCount(1))
|
|
|
|
|
|
.Build();
|
|
|
|
|
|
|
2024-01-13 16:17:48 +08:00
|
|
|
|
await scheduler.ScheduleJob(jobBuilder.Build(), trigger);
|
2024-01-12 17:18:39 +08:00
|
|
|
|
}
|
2023-12-11 09:55:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|