feat: 增加任务管理

This commit is contained in:
Argo-Tianyi 2021-12-29 11:21:56 +08:00
parent edf691a506
commit 5a61625f6f
5 changed files with 162 additions and 49 deletions

View File

@ -1,6 +1,7 @@
using BootstrapAdmin.Web.Services;
using BootstrapAdmin.Web.Services.SMS;
using BootstrapAdmin.Web.Services.SMS.Tencent;
using Longbow.Tasks;
using System.Text;
namespace Microsoft.Extensions.DependencyInjection
@ -83,6 +84,10 @@ namespace Microsoft.Extensions.DependencyInjection
// 增加 PetaPoco 数据服务
services.AddPetaPocoDataAccessServices();
// 增加后台任务
services.AddTaskServices();
services.AddHostedService<AdminTaskService>();
return services;
}
}

View File

@ -14,6 +14,5 @@ public static class TasksExtensions
LastRunResult = i.LastRunResult,
Status = i.Status,
Trigger = i.Triggers.First().ToString()
}).ToList();
}

View File

@ -1,5 +1,6 @@
@page "/Admin/Tasks"
<div class="tab-scroll-body">
<Card IsCollapsible="true" HeaderText="任务介绍" class="mb-3">
<CardBody>
<Alert class="mb-0">
@ -30,13 +31,21 @@
<AdminTable TItem="TasksModel" ExtendButtonColumnWidth="270" OnQueryAsync="OnQueryAsync">
<ColumnsTemplete>
<TableColumn @bind-Field="@context.Name" Sortable="true" Filterable="true" Searchable="true" Width="180"></TableColumn>
<TableColumn @bind-Field="@context.CreateTime" Sortable="true" Filterable="true" Searchable="true"></TableColumn>
<TableColumn @bind-Field="@context.LastRuntime" Sortable="true" Filterable="true" Searchable="true"></TableColumn>
<TableColumn @bind-Field="@context.NextRuntime" Sortable="true" Filterable="true" Searchable="true"></TableColumn>
<TableColumn @bind-Field="@context.Name" Sortable="true" Filterable="true" Searchable="true" Width="80"></TableColumn>
<TableColumn @bind-Field="@context.CreateTime" Sortable="true" Filterable="true" Searchable="true" FormatString="yyyy-MM-dd HH:mm:ss"></TableColumn>
<TableColumn @bind-Field="@context.LastRuntime" Sortable="true" Filterable="true" Searchable="true" FormatString="yyyy-MM-dd HH:mm:ss"></TableColumn>
<TableColumn @bind-Field="@context.NextRuntime" Sortable="true" Filterable="true" Searchable="true" FormatString="yyyy-MM-dd HH:mm:ss"></TableColumn>
<TableColumn @bind-Field="@context.Trigger" Sortable="true" Filterable="true" Searchable="true"></TableColumn>
<TableColumn @bind-Field="@context.LastRunResult" Sortable="true" Filterable="true" Searchable="true"></TableColumn>
<TableColumn @bind-Field="@context.Status" Sortable="true" Filterable="true" Searchable="true"></TableColumn>
<TableColumn @bind-Field="@context.LastRunResult" Sortable="true" Filterable="true" Searchable="true">
<Template Context="v">
<Tag Color="GetResultColor(v.Value)">@FormatResult(v.Value)</Tag>
</Template>
</TableColumn>
<TableColumn @bind-Field="@context.Status" Sortable="true" Filterable="true" Searchable="true">
<Template Context="v">
<Tag Color="GetStatusColor(v.Value)" Icon="@GetStatusIcon(v.Value)">@FormatStatus(v.Value)</Tag>
</Template>
</TableColumn>
</ColumnsTemplete>
<RowButtonTemplate>
<TableCellButton Size="Size.ExtraSmall" Color="Color.Warning" Icon="fa fa-pause-circle" Text="暂停" OnClick="() => OnPause(context)" />
@ -44,3 +53,4 @@
<TableCellButton Size="Size.ExtraSmall" Color="Color.Info" Icon="fa fa-info-circle" Text="日志" OnClick="() => OnLog(context)" />
</RowButtonTemplate>
</AdminTable>
</div>

View File

@ -1,4 +1,4 @@
using BootstrapAdmin.DataAccess.Models;
using BootstrapAdmin.Web.Components;
using BootstrapAdmin.Web.Extensions;
using BootstrapAdmin.Web.Models;
using Longbow.Tasks;
@ -7,7 +7,10 @@ namespace BootstrapAdmin.Web.Pages.Admin;
public partial class Tasks
{
private Task<QueryData<TasksModel>> OnQueryAsync(QueryPageOptions options)
[NotNull]
private AdminTable<TasksModel>? TaskTable { get; set; }
private static Task<QueryData<TasksModel>> OnQueryAsync(QueryPageOptions options)
{
var tasks = TaskServicesManager.ToList().ToTasksModelList();
return Task.FromResult(new QueryData<TasksModel>()
@ -16,17 +19,68 @@ public partial class Tasks
});
}
private Task OnPause(TasksModel model)
private static Color GetResultColor(TriggerResult result) => result switch
{
TriggerResult.Success => Color.Success,
TriggerResult.Error => Color.Danger,
TriggerResult.Timeout => Color.Warning,
TriggerResult.Cancelled => Color.Dark,
_ => Color.Primary
};
private static string FormatResult(TriggerResult result) => result switch
{
TriggerResult.Success => "成功",
TriggerResult.Error => "故障",
TriggerResult.Timeout => "超时",
TriggerResult.Cancelled => "取消",
_ => "未知状态"
};
private static Color GetStatusColor(SchedulerStatus status) => status switch
{
SchedulerStatus.Running => Color.Success,
SchedulerStatus.Ready => Color.Danger,
SchedulerStatus.Disabled => Color.Danger,
_ => Color.Primary
};
private static string FormatStatus(SchedulerStatus status) => status switch
{
SchedulerStatus.Running => "运行中",
SchedulerStatus.Ready => "已停止",
SchedulerStatus.Disabled => "禁用",
_ => "未知状态"
};
private static string GetStatusIcon(SchedulerStatus status) => status switch
{
SchedulerStatus.Running => "fa fa-play-circle",
SchedulerStatus.Ready => "fa fa-times-circle",
_ => "未知状态"
};
private static Task OnPause(TasksModel model)
{
var task = TaskServicesManager.ToList().FirstOrDefault(i => i.Name == model.Name);
if (task != null)
{
task.Status = SchedulerStatus.Ready;
}
return Task.CompletedTask;
}
private Task OnRun(TasksModel model)
private static Task OnRun(TasksModel model)
{
var task = TaskServicesManager.ToList().FirstOrDefault(i => i.Name == model.Name);
if (task != null)
{
task.Status = SchedulerStatus.Running;
}
return Task.CompletedTask;
}
private Task OnLog(TasksModel model)
private static Task OnLog(TasksModel model)
{
return Task.CompletedTask;
}

View File

@ -0,0 +1,45 @@
using BootstrapAdmin.DataAccess.Models;
using BootstrapAdmin.Web.Core;
using BootstrapAdmin.Web.Jobs;
using Longbow.Tasks;
namespace BootstrapAdmin.Web.Services;
class AdminTaskService : BackgroundService
{
private IDict DictService { get; set; }
/// <summary>
///
/// </summary>
/// <param name="dict"></param>
public AdminTaskService(IDict dict) => DictService = dict;
/// <summary>
/// 运行任务
/// </summary>
/// <param name="stoppingToken"></param>
/// <returns></returns>
protected override Task ExecuteAsync(CancellationToken stoppingToken) => Task.Run(() =>
{
TaskServicesManager.GetOrAdd("单次任务", token => Task.Delay(1000));
TaskServicesManager.GetOrAdd("周期任务", token => Task.Delay(1000), TriggerBuilder.Default.WithInterval(10000).Build());
TaskServicesManager.GetOrAdd("Cron 任务", token => Task.Delay(1000), TriggerBuilder.Build(Cron.Secondly(5)));
TaskServicesManager.GetOrAdd("超时任务", token => Task.Delay(2000), TriggerBuilder.Default.WithTimeout(1000).WithInterval(1000).WithRepeatCount(2).Build());
// 本机调试时此处会抛出异常,配置文件中默认开启了任务持久化到物理文件,此处异常只有首次加载时会抛出
// 此处异常是示例自定义任务内部未进行捕获异常时任务仍然能继续运行,不会导致整个进程崩溃退出
// 此处代码可注释掉
//TaskServicesManager.GetOrAdd("故障任务", token => throw new Exception("故障任务"));
TaskServicesManager.GetOrAdd("取消任务", token => Task.Delay(1000)).Triggers.First().Enabled = false;
// 创建任务并禁用
TaskServicesManager.GetOrAdd("禁用任务", token => Task.Delay(1000)).Status = SchedulerStatus.Disabled;
// 真实任务负责批次写入数据执行脚本到日志中
TaskServicesManager.GetOrAdd<DBLogTask>("SQL日志", TriggerBuilder.Build(Cron.Minutely()));
// 真实任务负责周期性设置健康检查结果开关为开启
TaskServicesManager.GetOrAdd("健康检查", token => Task.FromResult(DictService.SaveHealthCheck()), TriggerBuilder.Build(Cron.Minutely(10)));
});
}