wanggang
1 year ago
11 changed files with 244 additions and 223 deletions
@ -0,0 +1,11 @@ |
|||||
|
@echo off |
||||
|
|
||||
|
tasklist|find /i "SettleAccount.HttpApi.Host.exe" |
||||
|
|
||||
|
if %errorlevel% == 0 ( |
||||
|
exit |
||||
|
) |
||||
|
|
||||
|
%1 start mshta vbscript:createobject("wscript.shell").run("""%~0"" ::",0)(window.close)&&exit |
||||
|
|
||||
|
start /b SettleAccount.HttpApi.Host.exe --urls http://dev.ccwin-in.com:10582 |
@ -0,0 +1,3 @@ |
|||||
|
@ECHO OFF |
||||
|
|
||||
|
taskkill /im SettleAccount.HttpApi.Host.exe /f /t |
@ -0,0 +1,204 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Concurrent; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Diagnostics; |
||||
|
using System.Linq; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Cronos; |
||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Hosting; |
||||
|
using Win.Sfs.SettleAccount.Entities.BQ.Vmi; |
||||
|
|
||||
|
namespace Win.Sfs.SettleAccount.Entities.BQ; |
||||
|
|
||||
|
public class JobHostdService : BackgroundService |
||||
|
{ |
||||
|
private readonly object _lockObj = new object(); |
||||
|
private readonly IServiceProvider _serviceProvider; |
||||
|
private CancellationToken _stoppingToken; |
||||
|
|
||||
|
public JobHostdService(IServiceProvider serviceProvider) |
||||
|
{ |
||||
|
this._serviceProvider = serviceProvider; |
||||
|
} |
||||
|
|
||||
|
public static List<Type> ServiceTypes { get; private set; } |
||||
|
public ConcurrentDictionary<JobItem, Tuple<CancellationTokenSource, Thread>> Jobs { get; } = new(); |
||||
|
|
||||
|
public static void AddService(IServiceCollection services) |
||||
|
{ |
||||
|
ServiceTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(o => o.GetTypes()) |
||||
|
.Where(o => o.IsClass && !o.IsAbstract && o.IsAssignableTo(typeof(IJobService))) |
||||
|
.ToList(); |
||||
|
ServiceTypes.ForEach(o => |
||||
|
{ |
||||
|
services.AddTransient(typeof(IJobService), o); |
||||
|
services.AddTransient(o); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public void AddJob(JobItem job) |
||||
|
{ |
||||
|
lock (_lockObj) |
||||
|
{ |
||||
|
if (!Jobs.Keys.Any(o => o.Id == job.Id)) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
var source = new CancellationTokenSource(); |
||||
|
var token = source.Token; |
||||
|
var thread = new Thread(async () => |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
var expression = CronExpression.Parse(job.Cron, job.Cron.Split(' ').Length == 5 ? CronFormat.Standard : CronFormat.IncludeSeconds); |
||||
|
var serviceType = ServiceTypes.FirstOrDefault(o => o.FullName == job.Service); |
||||
|
if (serviceType != null) |
||||
|
{ |
||||
|
while (!_stoppingToken.IsCancellationRequested && !token.IsCancellationRequested) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
var now = DateTime.UtcNow; |
||||
|
var nextUtc = expression.GetNextOccurrence(now); |
||||
|
var span = nextUtc - now; |
||||
|
await Task.Delay(span.Value).ConfigureAwait(false); |
||||
|
Debug.WriteLine($"{job.Name} 定时任务开始执行"); |
||||
|
using var scope = this._serviceProvider.CreateScope(); |
||||
|
if (scope.ServiceProvider.GetService(serviceType) is IJobService jobService) |
||||
|
{ |
||||
|
if (!job.IsDisabled) |
||||
|
{ |
||||
|
var jobItem = this.GetJobItem(job.Id); |
||||
|
if (!jobItem.IsRunning) |
||||
|
{ |
||||
|
this.JobItemStart(job.Id); |
||||
|
} |
||||
|
try |
||||
|
{ |
||||
|
jobService.Invoke(); |
||||
|
this.JobItemSuccess(job.Id); |
||||
|
Debug.WriteLine($"{job.Name} 定时任务执行成功"); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
Debug.WriteLine($"{job.Name} 定时任务执行失败:{ex.Message}"); |
||||
|
Console.WriteLine(ex.ToString()); |
||||
|
this.JobItemFaild(job.Id, ex); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
Console.WriteLine(ex.ToString()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
Console.WriteLine(ex.ToString()); |
||||
|
} |
||||
|
}); |
||||
|
thread.IsBackground = true; |
||||
|
if (this.Jobs.TryAdd(job, new Tuple<CancellationTokenSource, Thread>(source, thread))) |
||||
|
{ |
||||
|
thread.Start(); |
||||
|
Debug.WriteLine($"{job.Name} 定时任务线程启动"); |
||||
|
} |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
Console.WriteLine(ex.ToString()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void JobItemFaild(Guid id, Exception ex) |
||||
|
{ |
||||
|
using var scope = this._serviceProvider.CreateScope(); |
||||
|
var db = scope.ServiceProvider.GetRequiredService<SettleAccountDbContext>(); |
||||
|
var entity = db.Set<JobItem>().FirstOrDefault(o => o.Id == id); |
||||
|
if (entity != null) |
||||
|
{ |
||||
|
entity.IsRunning = false; |
||||
|
var log = db.Set<JobLog>().FirstOrDefault(o => o.JobId == id); |
||||
|
log.End = DateTime.Now; |
||||
|
log.Success = false; |
||||
|
log.Exception = ex.ToString(); |
||||
|
db.SaveChanges(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void JobItemSuccess(Guid id) |
||||
|
{ |
||||
|
using var scope = this._serviceProvider.CreateScope(); |
||||
|
var db = scope.ServiceProvider.GetRequiredService<SettleAccountDbContext>(); |
||||
|
var entity = db.Set<JobItem>().FirstOrDefault(o => o.Id == id); |
||||
|
if (entity != null) |
||||
|
{ |
||||
|
entity.IsRunning = false; |
||||
|
var log = db.Set<JobLog>().FirstOrDefault(o => o.JobId == id); |
||||
|
log.End = DateTime.Now; |
||||
|
log.Success = true; |
||||
|
db.SaveChanges(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void JobItemStart(Guid id) |
||||
|
{ |
||||
|
using var scope = this._serviceProvider.CreateScope(); |
||||
|
var db = scope.ServiceProvider.GetRequiredService<SettleAccountDbContext>(); |
||||
|
var entity = db.Set<JobItem>().FirstOrDefault(o => o.Id == id); |
||||
|
if (entity != null) |
||||
|
{ |
||||
|
entity.IsRunning = true; |
||||
|
var log = db.Set<JobLog>().Add(new JobLog { Start = DateTime.Now, JobId = entity.Id }); |
||||
|
db.SaveChanges(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private JobItem GetJobItem(Guid id) |
||||
|
{ |
||||
|
using var scope = this._serviceProvider.CreateScope(); |
||||
|
return scope.ServiceProvider.GetRequiredService<SettleAccountDbContext>().Set<JobItem>().AsNoTracking().FirstOrDefault(o => o.Id == id); |
||||
|
} |
||||
|
|
||||
|
public void RemoveJob(JobItem item) |
||||
|
{ |
||||
|
lock (_lockObj) |
||||
|
{ |
||||
|
var key = this.Jobs.Keys.FirstOrDefault(o => o.Id == item.Id); |
||||
|
if (key != null) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
if (this.Jobs.TryRemove(key, out var value)) |
||||
|
{ |
||||
|
value.Item1.Cancel(); |
||||
|
value.Item2.Interrupt(); |
||||
|
value.Item2.Join(); |
||||
|
} |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
Console.WriteLine(ex.ToString()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected override Task ExecuteAsync(CancellationToken stoppingToken) |
||||
|
{ |
||||
|
this._stoppingToken = stoppingToken; |
||||
|
using var scope = this._serviceProvider.CreateScope(); |
||||
|
var db = scope.ServiceProvider.GetRequiredService<SettleAccountDbContext>(); |
||||
|
var jobs = db.Set<JobItem>().AsNoTracking().ToList(); |
||||
|
jobs.ForEach(this.AddJob); |
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue