Skip to content

Commit c468dff

Browse files
committed
Job Interrupt implemented
1 parent 6bd8d58 commit c468dff

File tree

15 files changed

+359
-317
lines changed

15 files changed

+359
-317
lines changed

demos/MainDemo/src/Syrna.QuartzAdmin.MainDemo.Jobs/AutoJob.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace Syrna.QuartzAdmin.MainDemo.Jobs
66
[QuartzTrigger(1, 0, "this is an job test", "_jobauto")]
77
public class AutoJob : IJob
88
{
9-
public async Task CanFireIt()
9+
private static async Task CanFireIt()
1010
{
1111
Random random = new();
1212
var randomNumber = random.Next(1, 100);
@@ -19,6 +19,7 @@ public async Task CanFireIt()
1919

2020
public async Task Execute(IJobExecutionContext context)
2121
{
22+
context.CancellationToken.ThrowIfCancellationRequested();
2223
Console.WriteLine($"Hello from AutoJob {DateTime.Now}");
2324

2425
await CanFireIt();

demos/MainDemo/src/Syrna.QuartzAdmin.MainDemo.Jobs/AutoJob1.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public class AutoJob1 : IJob
99
{
1010
public Task Execute(IJobExecutionContext context)
1111
{
12+
context.CancellationToken.ThrowIfCancellationRequested();
1213
Console.WriteLine($"Hello from Auto Job1 {DateTime.Now}");
1314

1415
context.SetIsSuccess(true);

demos/MainDemo/src/Syrna.QuartzAdmin.MainDemo.Jobs/AutoJob2.cs

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,27 @@
66
namespace Syrna.QuartzAdmin.MainDemo.Jobs
77
{
88
[QuartzTrigger(2,0, "this is an long job test", "_longjobauto")]
9-
public class AutoJob2 : IJob
9+
public class AutoJob2(ILogger<HelloJob> logger) : IJob
1010
{
11-
private readonly ILogger<HelloJob> _logger;
12-
13-
public AutoJob2(ILogger<HelloJob> logger)
14-
{
15-
_logger = logger;
16-
}
17-
1811
public async Task Execute(IJobExecutionContext context)
1912
{
20-
Console.WriteLine($"Hello from AutoJob {DateTime.Now}");
2113
context.CancellationToken.ThrowIfCancellationRequested();
14+
Console.WriteLine($"Hello from AutoJob {DateTime.Now}");
2215

2316
context.SetExecutionDetails("Executing first delay 30s");
24-
_logger.LogInformation("Delaying {delay} sec", 30);
17+
logger.LogInformation("Delaying {delay} sec", 30);
2518
await Task.Delay(30000);
2619

2720
context.SetExecutionDetails("Executing second delay 40s");
28-
_logger.LogInformation("Delaying {delay} sec", 40);
21+
logger.LogInformation("Delaying {delay} sec", 40);
2922
await Task.Delay(40000);
3023

3124
context.SetExecutionDetails("Executing third delay 50s");
32-
_logger.LogInformation("Delaying {delay} sec", 50);
25+
logger.LogInformation("Delaying {delay} sec", 50);
3326
await Task.Delay(50000);
3427

3528
context.SetExecutionDetails("Executing third delay 60s");
36-
_logger.LogInformation("Delaying {delay} sec", 60);
29+
logger.LogInformation("Delaying {delay} sec", 60);
3730
await Task.Delay(60000);
3831

3932
context.SetIsSuccess(true);

demos/MainDemo/src/Syrna.QuartzAdmin.MainDemo.Jobs/HelloJob.cs

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,43 +4,49 @@
44

55
namespace Syrna.QuartzAdmin.MainDemo.Jobs;
66

7-
public class HelloJob : IJob
7+
public class HelloJob(
8+
ILogger<HelloJob> logger,
9+
IDataMapValueResolver dmvResolver)
10+
: IJob
811
{
9-
public const string PropertyMessage = "message";
10-
public const string PropertyDelayInMs = "delay";
11-
12-
private readonly ILogger<HelloJob> _logger;
13-
private readonly IDataMapValueResolver _dmvResolver;
14-
15-
public HelloJob(ILogger<HelloJob> logger,
16-
IDataMapValueResolver dmvResolver)
17-
{
18-
_logger = logger;
19-
// to support resolving dynamic variables
20-
_dmvResolver = dmvResolver;
12+
private const string PropertyMessage = "message";
13+
private const string PropertyDelayInMs = "delay";
14+
15+
private async Task ExecuteJob(IJobExecutionContext context)
16+
{
17+
var rawMsg = context.GetDataMapValue(PropertyMessage);
18+
19+
// resolve dynamic variable
20+
var msg = dmvResolver.Resolve(rawMsg);
21+
22+
logger.LogInformation("Hello! {message}", msg);
23+
24+
if (context.MergedJobDataMap.TryGetIntValueFromString(PropertyDelayInMs, out var delay)
25+
&& delay > 0)
26+
{
27+
logger.LogInformation("Delaying {delay} ms", delay);
28+
await Task.Delay(delay, context.CancellationToken);
29+
}
30+
context.SetIsSuccess(true);
31+
context.SetReturnCode(0);
32+
context.SetExecutionDetails("Executed successfully");
33+
34+
// Write the output to display in execution log
35+
context.Result = $"Hello! {msg}";
2136
}
2237

2338
public async Task Execute(IJobExecutionContext context)
24-
{
25-
var rawMsg = context.GetDataMapValue(PropertyMessage);
26-
27-
// resolve dynamic variable
28-
var msg = _dmvResolver.Resolve(rawMsg);
29-
30-
_logger.LogInformation("Hello! {message}", msg);
31-
32-
if (context.MergedJobDataMap.TryGetIntValueFromString(PropertyDelayInMs, out var delay)
33-
&& delay > 0)
39+
{
40+
var taskCompletionSource = new TaskCompletionSource();
41+
context.CancellationToken.Register(() =>
3442
{
35-
_logger.LogInformation("Delaying {delay} ms", delay);
36-
await Task.Delay(delay);
37-
}
43+
// We received a cancellation message, cancel the TaskCompletionSource.Task
44+
// ReSharper disable once InvertIf
45+
taskCompletionSource.TrySetCanceled();
46+
});
47+
var completedTask = await Task.WhenAny(ExecuteJob(context), taskCompletionSource.Task);
3848

39-
// Write the output to display in execution log
40-
context.Result = $"Hello! {msg}";
41-
context.JobDetail.JobDataMap[JobDataMapKeys.IsSuccess] = true;
42-
context.JobDetail.JobDataMap[JobDataMapKeys.ReturnCode] = 0;
43-
context.JobDetail.JobDataMap[JobDataMapKeys.ExecutionDetails] = "Executed successfully";
49+
await completedTask;
4450
}
4551
}
4652

demos/MainDemo/src/Syrna.QuartzAdmin.MainDemo.Jobs/HttpJob.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public class HttpJob(IHttpClientFactory httpClientFactory,
1414
{
1515
public async Task Execute(IJobExecutionContext context)
1616
{
17+
context.CancellationToken.ThrowIfCancellationRequested();
1718
try
1819
{
1920
var data = context.MergedJobDataMap;

demos/MainDemo/src/Syrna.QuartzAdmin.MainDemo.Jobs/LongJob.cs

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,43 +4,48 @@
44

55
namespace Syrna.QuartzAdmin.MainDemo.Jobs;
66

7-
public class LongJob : IJob
7+
public class LongJob(
8+
ILogger<LongJob> logger,
9+
IDataMapValueResolver dmvResolver)
10+
: IJob
811
{
9-
public const string PropertyMessage = "message";
10-
public const string PropertyDelayInMs = "delay";
11-
12-
private readonly ILogger<HelloJob> _logger;
13-
private readonly IDataMapValueResolver _dmvResolver;
14-
15-
public LongJob(ILogger<HelloJob> logger,
16-
IDataMapValueResolver dmvResolver)
17-
{
18-
_logger = logger;
19-
// to support resolving dynamic variables
20-
_dmvResolver = dmvResolver;
21-
}
12+
private const string PropertyMessage = "message";
13+
private const string PropertyDelayInMs = "delay";
2214

2315
public async Task Execute(IJobExecutionContext context)
24-
{
25-
var rawMsg = context.GetDataMapValue(PropertyMessage);
16+
{
17+
var taskCompletionSource = new TaskCompletionSource();
18+
context.CancellationToken.Register(() =>
19+
{
20+
// We received a cancellation message, cancel the TaskCompletionSource.Task
21+
taskCompletionSource.TrySetCanceled();
22+
});
2623

27-
// resolve dynamic variable
28-
var msg = _dmvResolver.Resolve(rawMsg);
24+
var task = Task.Run(async () =>
25+
{
26+
var rawMsg = context.GetDataMapValue(PropertyMessage);
2927

30-
_logger.LogInformation("Hello! {message}", msg);
28+
// resolve dynamic variable
29+
var msg = dmvResolver.Resolve(rawMsg);
3130

32-
if (context.MergedJobDataMap.TryGetIntValueFromString(PropertyDelayInMs, out var delay)
33-
&& delay > 0)
34-
{
35-
_logger.LogInformation("Delaying {delay} ms", delay);
36-
await Task.Delay(delay);
37-
}
38-
39-
// Write the output to display in execution log
40-
context.Result = $"Hello! {msg}";
41-
context.JobDetail.JobDataMap[JobDataMapKeys.IsSuccess] = true;
42-
context.JobDetail.JobDataMap[JobDataMapKeys.ReturnCode] = 0;
43-
context.JobDetail.JobDataMap[JobDataMapKeys.ExecutionDetails] = "Executed successfully";
31+
logger.LogInformation("Hello! {message}", msg);
32+
33+
if (context.MergedJobDataMap.TryGetIntValueFromString(PropertyDelayInMs, out var delay)
34+
&& delay > 0)
35+
{
36+
logger.LogInformation("Delaying {delay} ms", delay);
37+
await Task.Delay(delay, context.CancellationToken);
38+
}
39+
40+
// Write the output to display in execution log
41+
context.Result = $"Hello! {msg}";
42+
context.JobDetail.JobDataMap[JobDataMapKeys.IsSuccess] = true;
43+
context.JobDetail.JobDataMap[JobDataMapKeys.ReturnCode] = 0;
44+
context.JobDetail.JobDataMap[JobDataMapKeys.ExecutionDetails] = "Executed successfully";
45+
});
46+
var completedTask = await Task.WhenAny(task, taskCompletionSource.Task);
47+
48+
await completedTask;
4449
}
4550
}
4651

modules/src/Syrna.QuartzAdmin.Blazor/Pages/QuartzAdmin/History/History.razor

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,12 +150,12 @@
150150
</Addons>
151151
</BarEnd>
152152
</Bar>
153-
<DataGrid @ref="table"
153+
<DataGrid @ref="_table"
154154
TItem="ExecutionLogDto"
155-
Data="@pagedData"
155+
Data="@_pagedData"
156156
ReadData="@OnReadData"
157-
TotalItems="@totalItems"
158-
PageSize="@pageSize"
157+
TotalItems="@_totalItems"
158+
PageSize="@_pageSize"
159159
Editable="false"
160160
ShowPager
161161
FixedHeader
@@ -183,6 +183,15 @@
183183
var iconAndColor = GetLogIconAndColor(context);
184184
}
185185
<Icon Name="@iconAndColor.Item1" TextColor="@iconAndColor.Item2" title="@iconAndColor.Item3" IconSize="IconSize.Default" />
186+
@if (context.IsSuccess is null && context.LogType == LogType.ScheduleJob)
187+
{
188+
<Tooltip FadeDuration="1000" Text="@L["HistoryMenu:InterruptJob"]">
189+
<Button Clicked="@(async () => await OnInterruptScheduleJob(context))"
190+
aria-label="@L["HistoryMenu:InterruptJob"]">
191+
<Icon Name="@IconName.Stop" IconSize="IconSize.Default"></Icon>
192+
</Button>
193+
</Tooltip>
194+
}
186195
</DisplayTemplate>
187196
</DataGridColumn>
188197
<DataGridDateColumn Field="@nameof(ExecutionLogDto.DateAddedUtc)" Caption="@L["ExecutionLog:DateAddedUtc"]" Width="160px">
@@ -234,4 +243,4 @@
234243
</DataGridColumn>
235244
</DataGridColumns>
236245
</DataGrid>
237-
<ExecutionDetailsDialog @ref="ExecutionDetailsDialogRef"></ExecutionDetailsDialog>
246+
<ExecutionDetailsDialog @ref="_executionDetailsDialogRef"></ExecutionDetailsDialog>

modules/src/Syrna.QuartzAdmin.Blazor/Pages/QuartzAdmin/History/History.razor.cs

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
using Blazorise;
22
using Blazorise.DataGrid;
3+
using Localization.Resources.AbpUi;
34
using Microsoft.AspNetCore.Components;
45
using Microsoft.Extensions.Localization;
56
using Syrna.QuartzAdmin.Blazor.Components;
67
using Syrna.QuartzAdmin.ExecutionLog;
78
using Syrna.QuartzAdmin.ExecutionLog.Dtos;
89
using Syrna.QuartzAdmin.Localization;
10+
using Syrna.QuartzAdmin.Scheduler;
911
using System;
1012
using System.Collections.Generic;
1113
using System.Linq;
@@ -16,15 +18,17 @@ namespace Syrna.QuartzAdmin.Blazor.Pages.QuartzAdmin.History
1618
public partial class History
1719
{
1820
[Inject] protected new IStringLocalizer<QuartzAdminResource> L { get; set; }
19-
[Inject] IExecutionLogAppService LogSvc { get; set; } = null!;
21+
[Inject] private IExecutionLogAppService LogSvc { get; set; } = null!;
22+
[Inject] private ISchedulerAppService SchedulerSvc { get; set; } = null!;
23+
[Inject] protected IStringLocalizer<AbpUiResource> UiLocalizer { get; set; }
2024

21-
private IEnumerable<ExecutionLogDto> pagedData;
22-
private DataGrid<ExecutionLogDto> table = null!;
25+
private IEnumerable<ExecutionLogDto> _pagedData;
26+
private DataGrid<ExecutionLogDto> _table = null!;
2327

2428
private long _firstLogId;
2529

26-
private int totalItems;
27-
private int pageSize = 10;
30+
private int _totalItems;
31+
private readonly int _pageSize = 10;
2832
private bool _openFilter;
2933

3034
private ExecutionLogFilter _filter = new();
@@ -35,18 +39,10 @@ public partial class History
3539
private IEnumerable<string> _triggerNames = [];
3640
private IEnumerable<string> _triggerGroups = [];
3741

38-
public async Task OnReadData()
42+
private async Task OnReadData()
3943
{
40-
PageMetadata pageMeta;
41-
var state = await table.GetState();
42-
if (pagedData == null)
43-
{
44-
pageMeta = PageMetadata.New(0, state.PageSize);
45-
}
46-
else
47-
{
48-
pageMeta = new PageMetadata { Page = state.CurrentPage - 1, PageSize = state.PageSize };
49-
}
44+
var state = await _table.GetState();
45+
var pageMeta = _pagedData == null ? PageMetadata.New(0, state.PageSize) : new PageMetadata { Page = state.CurrentPage - 1, PageSize = state.PageSize };
5046
var args = new ExecutionLogReadArgs
5147
{
5248
Filter = _filter,
@@ -60,8 +56,8 @@ public async Task OnReadData()
6056
_firstLogId = data.Items.FirstOrDefault()?.Id ?? 0;
6157
}
6258

63-
totalItems = (int)data.TotalCount;
64-
pagedData = data.Items;
59+
_totalItems = (int)data.TotalCount;
60+
_pagedData = data.Items;
6561
}
6662

6763
private async Task OnSearch(string text)
@@ -72,9 +68,9 @@ private async Task OnSearch(string text)
7268

7369
public async Task RefreshLogs()
7470
{
75-
pagedData = null;
71+
_pagedData = null;
7672
_firstLogId = 0;
77-
await table.ReadData.InvokeAsync();
73+
await _table.ReadData.InvokeAsync();
7874
}
7975

8076
private static (IconName, TextColor, string) GetLogIconAndColor(ExecutionLogDto log)
@@ -102,10 +98,28 @@ private static (IconName, TextColor, string) GetLogIconAndColor(ExecutionLogDto
10298
}
10399
}
104100

105-
ExecutionDetailsDialog ExecutionDetailsDialogRef;
101+
private async Task OnInterruptScheduleJob(ExecutionLogDto log)
102+
{
103+
if (log.FireInstanceId == null)
104+
{
105+
await Notify.Error(L["CannotInterruptJob"]);
106+
return;
107+
}
108+
109+
if (await SchedulerSvc.InterruptJob(log.FireInstanceId))
110+
{
111+
await Notify.Info(UiLocalizer["InterruptJobSuccessfully"]);
112+
}
113+
else
114+
{
115+
await Notify.Error(L["InterruptJobFailed"]);
116+
}
117+
}
118+
119+
private ExecutionDetailsDialog _executionDetailsDialogRef;
106120
private async Task OnMoreDetails(ExecutionLogDto log, string titleSuffix)
107121
{
108-
await ExecutionDetailsDialogRef.OpenModalAsync(log, titleSuffix);
122+
await _executionDetailsDialogRef.OpenModalAsync(log, titleSuffix);
109123
}
110124

111125
public History()

0 commit comments

Comments
 (0)