Refactor Jobs API
This commit is contained in:
parent
87f836b0e3
commit
059356029d
19
src/core/Elsa.Jobs/Abstractions/Job.cs
Normal file
19
src/core/Elsa.Jobs/Abstractions/Job.cs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
using System.Threading.Tasks;
|
||||
using Elsa.Jobs.Models;
|
||||
|
||||
namespace Elsa.Jobs.Contracts;
|
||||
|
||||
public abstract class Job : IJob
|
||||
{
|
||||
ValueTask IJob.ExecuteAsync(JobExecutionContext context) => ExecuteAsync(context);
|
||||
|
||||
protected virtual ValueTask ExecuteAsync(JobExecutionContext context)
|
||||
{
|
||||
Execute(context);
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
|
||||
protected virtual void Execute(JobExecutionContext context)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Jobs.Contracts;
|
||||
|
||||
namespace Elsa.Jobs.Abstractions;
|
||||
|
||||
public abstract class JobHandler<T> : IJobHandler where T : IJob
|
||||
{
|
||||
public bool GetSupports(IJob job) => job is T;
|
||||
|
||||
public virtual Task HandleAsync(IJob job, CancellationToken cancellationToken) => HandleAsync((T)job, cancellationToken);
|
||||
|
||||
protected virtual Task HandleAsync(T job, CancellationToken cancellationToken)
|
||||
{
|
||||
Handle();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
protected virtual void Handle()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
using System.Threading.Tasks;
|
||||
using Elsa.Jobs.Models;
|
||||
|
||||
namespace Elsa.Jobs.Contracts;
|
||||
|
||||
public interface IJob
|
||||
{
|
||||
string JobId { get; }
|
||||
ValueTask ExecuteAsync(JobExecutionContext context);
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Elsa.Jobs.Contracts;
|
||||
|
||||
public interface IJobHandler
|
||||
{
|
||||
bool GetSupports(IJob job);
|
||||
Task HandleAsync(IJob job, CancellationToken cancellationToken);
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ namespace Elsa.Jobs.Contracts;
|
|||
|
||||
public interface IJobScheduler
|
||||
{
|
||||
Task ScheduleAsync(IJob job, ISchedule schedule, string[]? groupKeys = default, CancellationToken cancellationToken = default);
|
||||
Task UnscheduleAsync(IJob job, CancellationToken cancellationToken = default);
|
||||
Task ScheduleAsync(IJob job, string name, ISchedule schedule, string[]? groupKeys = default, CancellationToken cancellationToken = default);
|
||||
Task UnscheduleAsync(string name, CancellationToken cancellationToken = default);
|
||||
Task ClearAsync(string[]? groupKeys = default, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ namespace Elsa.Jobs.Extensions;
|
|||
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
public static IServiceCollection AddJobs(this IServiceCollection services, IJobSchedulerProvider schedulerProvider, IJobQueueProvider queueProvider)
|
||||
public static IServiceCollection AddJobServices(this IServiceCollection services, IJobSchedulerProvider schedulerProvider, IJobQueueProvider queueProvider)
|
||||
{
|
||||
services
|
||||
.AddSingleton<IJobSerializer, JobSerializer>()
|
||||
|
|
@ -16,6 +16,4 @@ public static class ServiceCollectionExtensions
|
|||
queueProvider.ConfigureServices(services);
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddJobHandler<T>(this IServiceCollection services) where T : class, IJobHandler => services.AddSingleton<IJobHandler, T>();
|
||||
}
|
||||
19
src/core/Elsa.Jobs/Models/JobExecutionContext.cs
Normal file
19
src/core/Elsa.Jobs/Models/JobExecutionContext.cs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.Jobs.Models;
|
||||
|
||||
public class JobExecutionContext
|
||||
{
|
||||
public JobExecutionContext(IServiceProvider serviceProvider, CancellationToken cancellation)
|
||||
{
|
||||
ServiceProvider = serviceProvider;
|
||||
Cancellation = cancellation;
|
||||
}
|
||||
|
||||
public IServiceProvider ServiceProvider { get; }
|
||||
public CancellationToken Cancellation { get; }
|
||||
|
||||
public T GetRequiredService<T>() where T : notnull => ServiceProvider.GetRequiredService<T>();
|
||||
}
|
||||
|
|
@ -1,28 +1,23 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Jobs.Contracts;
|
||||
using Elsa.Jobs.Models;
|
||||
|
||||
namespace Elsa.Jobs.Services;
|
||||
|
||||
public class JobRunner : IJobRunner
|
||||
{
|
||||
private readonly IEnumerable<IJobHandler> _handlers;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public JobRunner(IEnumerable<IJobHandler> handlers)
|
||||
public JobRunner(IServiceProvider serviceProvider)
|
||||
{
|
||||
_handlers = handlers;
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public async Task RunJobAsync(IJob job, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var handler = _handlers.FirstOrDefault(x => x.GetSupports(job));
|
||||
|
||||
if (handler == null)
|
||||
throw new NotSupportedException($"The specified job of type {job.GetType().Name} does not have a handler");
|
||||
|
||||
await handler.HandleAsync(job, cancellationToken);
|
||||
var context = new JobExecutionContext(_serviceProvider, cancellationToken);
|
||||
await job.ExecuteAsync(context);
|
||||
}
|
||||
}
|
||||
|
|
@ -24,16 +24,16 @@ public class QuartzJobScheduler : IJobScheduler
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task ScheduleAsync(IJob job, IElsaSchedule schedule, string[]? groupKeys, CancellationToken cancellationToken = default)
|
||||
public async Task ScheduleAsync(IJob job, string name, IElsaSchedule schedule, string[]? groupKeys, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var quartzTrigger = CreateTrigger(job, schedule, groupKeys);
|
||||
var quartzTrigger = CreateTrigger(job, name, schedule, groupKeys);
|
||||
await ScheduleJob(quartzTrigger, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task UnscheduleAsync(IJob job, CancellationToken cancellationToken = default)
|
||||
public async Task UnscheduleAsync(string name, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var scheduler = await _schedulerFactory.GetScheduler(cancellationToken);
|
||||
var triggerKey = new TriggerKey(job.JobId);
|
||||
var triggerKey = new TriggerKey(name);
|
||||
await scheduler.UnscheduleJob(triggerKey, cancellationToken);
|
||||
}
|
||||
|
||||
|
|
@ -60,11 +60,11 @@ public class QuartzJobScheduler : IJobScheduler
|
|||
}
|
||||
}
|
||||
|
||||
private ITrigger CreateTrigger(IJob job, IElsaSchedule schedule, string[]? groupKeys)
|
||||
private ITrigger CreateTrigger(IJob job, string name, IElsaSchedule schedule, string[]? groupKeys)
|
||||
{
|
||||
var jobName = job.GetType().Name;
|
||||
var groupKey = BuildGroupKey(groupKeys);
|
||||
var triggerKey = new TriggerKey(job.JobId, groupKey);
|
||||
var triggerKey = new TriggerKey(name, groupKey);
|
||||
var json = _jobSerializer.Serialize(job);
|
||||
var builder = TriggerBuilder.Create().ForJob(jobName).WithIdentity(triggerKey).UsingJobData(JobDataKey, json);
|
||||
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@ public static class ServiceCollectionExtensions
|
|||
services
|
||||
.AddSingleton<IWorkflowTriggerScheduler, WorkflowTriggerScheduler>()
|
||||
.AddSingleton<IWorkflowBookmarkScheduler, WorkflowBookmarkScheduler>()
|
||||
.AddJobHandler<RunWorkflowJobHandler>()
|
||||
.AddJobHandler<ResumeWorkflowJobHandler>()
|
||||
.AddNotificationHandlersFrom<ScheduleWorkflows>()
|
||||
.AddHostedService<ScheduleWorkflows>();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,26 +1,33 @@
|
|||
using System.Threading;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Models;
|
||||
using Elsa.Runtime.Contracts;
|
||||
using Elsa.Runtime.Models;
|
||||
using Elsa.Jobs.Abstractions;
|
||||
using Elsa.Jobs.Contracts;
|
||||
using Elsa.Jobs.Models;
|
||||
|
||||
namespace Elsa.Modules.Scheduling.Jobs;
|
||||
|
||||
public record ResumeWorkflowJob(string WorkflowInstanceId, Bookmark Bookmark) : IJob
|
||||
public class ResumeWorkflowJob : Job
|
||||
{
|
||||
public string JobId => $"Bookmark:{Bookmark.Id}";
|
||||
}
|
||||
|
||||
public class ResumeWorkflowJobHandler : JobHandler<ResumeWorkflowJob>
|
||||
{
|
||||
private readonly IWorkflowInvoker _workflowInvoker;
|
||||
public ResumeWorkflowJobHandler(IWorkflowInvoker workflowInvoker) => _workflowInvoker = workflowInvoker;
|
||||
|
||||
protected override async Task HandleAsync(ResumeWorkflowJob job, CancellationToken cancellationToken)
|
||||
[JsonConstructor]
|
||||
public ResumeWorkflowJob()
|
||||
{
|
||||
var request = new DispatchWorkflowInstanceRequest(job.WorkflowInstanceId, job.Bookmark);
|
||||
await _workflowInvoker.DispatchAsync(request, cancellationToken);
|
||||
}
|
||||
|
||||
public ResumeWorkflowJob(string workflowInstanceId, Bookmark bookmark)
|
||||
{
|
||||
WorkflowInstanceId = workflowInstanceId;
|
||||
Bookmark = bookmark;
|
||||
}
|
||||
|
||||
public string WorkflowInstanceId { get; set; } = default!;
|
||||
public Bookmark Bookmark { get; set; } = default!;
|
||||
|
||||
protected override async ValueTask ExecuteAsync(JobExecutionContext context)
|
||||
{
|
||||
var request = new DispatchWorkflowInstanceRequest(WorkflowInstanceId, Bookmark);
|
||||
var workflowInvoker = context.GetRequiredService<IWorkflowInvoker>();
|
||||
await workflowInvoker.DispatchAsync(request, context.Cancellation);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +1,30 @@
|
|||
using System.Threading;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Runtime.Contracts;
|
||||
using Elsa.Runtime.Models;
|
||||
using Elsa.Jobs.Abstractions;
|
||||
using Elsa.Jobs.Contracts;
|
||||
using Elsa.Jobs.Models;
|
||||
|
||||
namespace Elsa.Modules.Scheduling.Jobs;
|
||||
|
||||
public record RunWorkflowJob(string WorkflowId) : IJob
|
||||
public class RunWorkflowJob : Job
|
||||
{
|
||||
public string JobId => WorkflowId;
|
||||
}
|
||||
|
||||
public class RunWorkflowJobHandler : JobHandler<RunWorkflowJob>
|
||||
{
|
||||
private readonly IWorkflowInvoker _workflowInvoker;
|
||||
|
||||
public RunWorkflowJobHandler(IWorkflowInvoker workflowInvoker)
|
||||
[JsonConstructor]
|
||||
public RunWorkflowJob()
|
||||
{
|
||||
_workflowInvoker = workflowInvoker;
|
||||
}
|
||||
|
||||
protected override async Task HandleAsync(RunWorkflowJob job, CancellationToken cancellationToken)
|
||||
public RunWorkflowJob(string workflowId)
|
||||
{
|
||||
var request = new DispatchWorkflowDefinitionRequest(job.WorkflowId, 1);
|
||||
await _workflowInvoker.DispatchAsync(request, cancellationToken);
|
||||
WorkflowId = workflowId;
|
||||
}
|
||||
|
||||
public string WorkflowId { get; set; } = default!;
|
||||
|
||||
protected override async ValueTask ExecuteAsync(JobExecutionContext context)
|
||||
{
|
||||
var request = new DispatchWorkflowDefinitionRequest(WorkflowId, 1);
|
||||
var workflowInvoker = context.GetRequiredService<IWorkflowInvoker>();
|
||||
await workflowInvoker.DispatchAsync(request, context.Cancellation);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue