Skip to content

Commit

Permalink
优化MyApp任务调度代码
Browse files Browse the repository at this point in the history
  • Loading branch information
zhontai committed Dec 16, 2024
1 parent 9359b10 commit b454786
Showing 1 changed file with 5 additions and 186 deletions.
191 changes: 5 additions & 186 deletions templates/admin/content/src/MyApp.Host/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,39 +26,11 @@
using AdminDbKeys = ZhonTai.Admin.Core.Consts.DbKeys;
#if (!NoTaskScheduler)
using ZhonTai.Admin.Core.Db;
using ZhonTai.Admin.Domain;
using System;
using Cronos;
using Microsoft.Extensions.Options;
using Newtonsoft.Json.Linq;
using System.Diagnostics;
using ZhonTai.Admin.Services.Email;
using ZhonTai.Admin.Services.TaskScheduler;
using ZhonTai.Admin.Services.Email.Events;
using Mapster;
#endif
using Autofac;
using MyApp.Api.Core.Repositories;
using System.Text;
#if (!NoTaskScheduler)

static void ConfigureScheduler(IFreeSql fsql)
{
fsql.CodeFirst
.ConfigEntity<TaskInfo>(a =>
{
a.Name("app_task");
})
.ConfigEntity<TaskLog>(a =>
{
a.Name("app_task_log");
})
.ConfigEntity<TaskInfoExt>(a =>
{
a.Name("app_task_ext");
});
}
#endif

new HostApp(new HostAppOptions()
{
Expand All @@ -68,7 +40,7 @@ static void ConfigureScheduler(IFreeSql fsql)
#if (!NoTaskScheduler)
if (dbConfig.Key == AdminDbKeys.TaskDb)
{
freeSql.SyncSchedulerStructure(dbConfig, ConfigureScheduler);
freeSql.SyncSchedulerStructure(dbConfig, TaskSchedulerServiceExtensions.ConfigureScheduler);
}
#endif
},
Expand Down Expand Up @@ -97,83 +69,16 @@ static void ConfigureScheduler(IFreeSql fsql)
//添加任务调度,默认使用权限库作为任务调度库
context.Services.AddTaskScheduler(AdminDbKeys.TaskDb, options =>
{
options.ConfigureFreeSql = ConfigureScheduler;
options.ConfigureFreeSql = TaskSchedulerServiceExtensions.ConfigureScheduler;

//配置任务调度
options.ConfigureFreeSchedulerBuilder = freeSchedulerBuilder =>
{
void OnExecuting(TaskInfo task)
{
var taskSchedulerConfig = AppInfo.GetRequiredService<IOptions<TaskSchedulerConfig>>().Value;

if (task.Topic?.StartsWith("[shell]") == true)
{
var jsonArgs = JToken.Parse(task.Body);
var shellArgs = jsonArgs.Adapt<ShellArgs>();

var arguments = shellArgs.Arguments;
var modeulName = jsonArgs["moduleName"]?.ToString();
if (modeulName.NotNull())
{
//通过moduleName获取配置文件moduleName对应的Grpc远程地址
var grpcAddress = string.Empty;
if (grpcAddress.NotNull())
{
arguments = arguments.Replace("${grpcAddress}", grpcAddress, StringComparison.OrdinalIgnoreCase);
}
}

var fileName = shellArgs.FileName;
if (fileName.IsNull())
{
fileName = taskSchedulerConfig?.ProcessStartInfo?.FileName;
}

var workingDirectory = shellArgs.WorkingDirectory;
if (workingDirectory.IsNull())
{
workingDirectory = taskSchedulerConfig?.ProcessStartInfo?.WorkingDirectory;
}

var startInfo = new ProcessStartInfo
{
FileName = fileName,
Arguments = arguments,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
WorkingDirectory = workingDirectory,
StandardOutputEncoding = Encoding.UTF8,
StandardErrorEncoding = Encoding.UTF8,
};

var response = string.Empty;
var error = string.Empty;
using (var process = Process.Start(startInfo))
{
response = process.StandardOutput.ReadToEnd();
error = process.StandardError.ReadToEnd();

//if (response.NotNull())
//{
// Console.WriteLine("Response:");
// Console.WriteLine(response);
//}

//if (error.NotNull())
//{
// Console.WriteLine("Error:");
// Console.WriteLine(error);
//}

process.WaitForExit();
}

if (response.NotNull())
task.Remark(response);

if (error.NotNull())
throw new Exception(error);
TaskSchedulerServiceExtensions.ExecutGrpc(task);
}
}

Expand All @@ -189,102 +94,16 @@ void OnExecuting(TaskInfo task)
var taskInfo = taskService.GetAsync(task.Id).Result;

//失败重试
if (taskInfo != null && taskInfo.FailRetryCount > 0)
{
var retryRound = 0;
var failRetryCount = taskInfo.FailRetryCount;
var failRetryInterval = taskInfo.FailRetryInterval > 0 ? taskInfo.FailRetryInterval.Value : 10;
var scheduler = AppInfo.GetRequiredService<Scheduler>();
var currentRound = taskLog.Round;
void OnFailedCallBak()
{
failRetryCount--;
retryRound++;
var startdt = DateTime.UtcNow;
var result = new TaskLog
{
CreateTime = DateTime.UtcNow.Add(scheduler.TimeOffset),
TaskId = task.Id,
Round = currentRound,
Remark = $"第{retryRound}次失败重试",
Success = true
};

try
{
OnExecuting(task);
}
catch (Exception ex)
{
result.Success = false;
result.Exception = ex.InnerException == null ? $"{ex.Message}\r\n{ex.StackTrace}" : $"{ex.Message}\r\n{ex.StackTrace}\r\n\r\nInnerException: {ex.InnerException.Message}\r\n{ex.InnerException.StackTrace}";

if (failRetryCount > 0)
{
scheduler.AddTempTask(TimeSpan.FromSeconds(failRetryInterval), OnFailedCallBak);
}
}
finally
{
result.ElapsedMilliseconds = (long)DateTime.UtcNow.Subtract(startdt).TotalMilliseconds;
var taskLogService = AppInfo.GetRequiredService<TaskLogService>();
taskLogService.Add(result);
}
}

scheduler.AddTempTask(TimeSpan.FromSeconds(failRetryInterval), OnFailedCallBak);
}
TaskSchedulerServiceExtensions.FailedRetry(taskInfo, task, taskLog, OnExecuting);

//发送告警邮件
var alarmEmail = taskInfo?.AlarmEmail;
var taskSchedulerConfig = AppInfo.GetRequiredService<IOptionsMonitor<TaskSchedulerConfig>>().CurrentValue;
if (taskSchedulerConfig.AlerEmail != null && taskSchedulerConfig.AlerEmail.Enable)
{
var emailService = AppInfo.GetRequiredService<EmailService>();
if (alarmEmail.IsNull())
{
alarmEmail = taskSchedulerConfig.AlerEmail.Address;
}
var topic = task.Topic;
if (alarmEmail.NotNull())
{
var jsonArgs = JToken.Parse(task.Body);
var desc = jsonArgs["desc"]?.ToString();
if (desc.NotNull())
topic = desc;
}
alarmEmail?.Split(',')?.ToList()?.ForEach(async address =>
{
await emailService.SingleSendAsync(new EmailSingleSendEvent
{
ToEmail = new EmailSingleSendEvent.Models.EmailModel
{
Address = address,
Name = address
},
Subject = "【任务调度中心】监控报警",
Body = $@"<p>任务名称:{topic}</p>
<p>任务编号:{task.Id}</p>
<p>告警类型:调度失败</p>
<p>告警内容:<br/>{taskLog.Exception}</p>"
});
});
}
TaskSchedulerServiceExtensions.SendAlarmEmail(taskInfo, task, taskLog);
}
}
catch (Exception ex)
{
AppInfo.Log.Error(ex);
}
})
.UseCustomInterval(task =>
{
//自定义间隔
var expression = CronExpression.Parse(task.IntervalArgument, CronFormat.IncludeSeconds);
var next = expression.GetNextOccurrence(DateTimeOffset.Now, TimeZoneInfo.Local);
var nextLocalTime = next?.DateTime;

return nextLocalTime == null ? null : nextLocalTime - DateTime.Now;
});
};
});
Expand Down

0 comments on commit b454786

Please sign in to comment.