-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
(hangfire): #33 en-/disable jobs by ms feature management
reworked: UniquePerQueueAttribute, so it does a deep compare of the jobs method parameters added: JobCleanupExpirationTimeAttribute to be able to control how long job results are kept until deletion added: documentation about the new attributes and filters added: unit tests for new features and improved coverage on existing code
- Loading branch information
Showing
18 changed files
with
582 additions
and
95 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
37 changes: 37 additions & 0 deletions
37
...lugins/Jobs/Hangfire/src/PiBox.Plugins.Jobs.Hangfire/Attributes/EnabledByFeatureFilter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
using Hangfire.Common; | ||
using Hangfire.Server; | ||
using Microsoft.Extensions.Logging; | ||
using Microsoft.FeatureManagement; | ||
|
||
namespace PiBox.Plugins.Jobs.Hangfire.Attributes | ||
{ | ||
/// <summary> | ||
/// Decide if to execute a job by enabled featured | ||
/// </summary> | ||
internal class EnabledByFeatureFilter : JobFilterAttribute, IServerFilter | ||
{ | ||
private readonly IFeatureManager _featureManager; | ||
private readonly ILogger<EnabledByFeatureFilter> _logger; | ||
|
||
public EnabledByFeatureFilter(IFeatureManager featureManager, ILogger<EnabledByFeatureFilter> logger) | ||
{ | ||
_featureManager = featureManager; | ||
_logger = logger; | ||
Order = 0; | ||
} | ||
|
||
public void OnPerforming(PerformingContext context) | ||
{ | ||
var jobName = context.BackgroundJob.Job.Type.Name; | ||
if (_featureManager.IsEnabledAsync(jobName).Result) return; | ||
_logger.LogWarning("Execution of job {JobName} was cancelled due to not enabled feature {FeatureName}", | ||
jobName, jobName); | ||
context.Canceled = true; | ||
} | ||
|
||
public void OnPerformed(PerformedContext context) | ||
{ | ||
// do nothing | ||
} | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
.../Hangfire/src/PiBox.Plugins.Jobs.Hangfire/Attributes/JobCleanupExpirationTimeAttribute.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
using Hangfire.Common; | ||
using Hangfire.States; | ||
using Hangfire.Storage; | ||
|
||
namespace PiBox.Plugins.Jobs.Hangfire.Attributes | ||
{ | ||
public class JobCleanupExpirationTimeAttribute : JobFilterAttribute, IApplyStateFilter | ||
{ | ||
private readonly int _cleanUpAfterDays; | ||
|
||
public JobCleanupExpirationTimeAttribute(int cleanUpAfterDays) | ||
{ | ||
_cleanUpAfterDays = cleanUpAfterDays; | ||
Order = 100; | ||
} | ||
|
||
public void OnStateApplied(ApplyStateContext context, IWriteOnlyTransaction transaction) | ||
{ | ||
context.JobExpirationTimeout = TimeSpan.FromDays(_cleanUpAfterDays); | ||
} | ||
|
||
public void OnStateUnapplied(ApplyStateContext context, IWriteOnlyTransaction transaction) | ||
{ | ||
// nothing to do here | ||
} | ||
} | ||
} |
2 changes: 1 addition & 1 deletion
2
...ns.Jobs.Hangfire/RecurringJobAttribute.cs → ...gfire/Attributes/RecurringJobAttribute.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
95 changes: 95 additions & 0 deletions
95
...ugins/Jobs/Hangfire/src/PiBox.Plugins.Jobs.Hangfire/Attributes/UniquePerQueueAttribute.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
using System.Text.Json; | ||
using Hangfire; | ||
using Hangfire.Common; | ||
using Hangfire.States; | ||
using Hangfire.Storage; | ||
using Hangfire.Storage.Monitoring; | ||
|
||
namespace PiBox.Plugins.Jobs.Hangfire.Attributes | ||
{ | ||
public class UniquePerQueueAttribute : JobFilterAttribute, IElectStateFilter | ||
{ | ||
public string Queue { get; set; } | ||
|
||
public bool CheckScheduledJobs { get; set; } | ||
|
||
public bool CheckRunningJobs { get; set; } | ||
|
||
public UniquePerQueueAttribute(string queue) | ||
{ | ||
Queue = queue; | ||
Order = 10; | ||
} | ||
|
||
private IEnumerable<JobEntity> GetJobs(ElectStateContext context) | ||
{ | ||
IMonitoringApi monitoringApi = context.Storage.GetMonitoringApi(); | ||
List<JobEntity> jobs = | ||
new List<JobEntity>(); | ||
foreach ((string key, EnqueuedJobDto enqueuedJobDto1) in monitoringApi.EnqueuedJobs(Queue, 0, 500)) | ||
{ | ||
string id = key; | ||
EnqueuedJobDto enqueuedJobDto2 = enqueuedJobDto1; | ||
jobs.Add(JobEntity.Parse(id, enqueuedJobDto2.Job)); | ||
} | ||
|
||
if (CheckScheduledJobs) | ||
{ | ||
foreach (KeyValuePair<string, ScheduledJobDto> pair in monitoringApi.ScheduledJobs(0, 500)) | ||
{ | ||
string id = pair.Key; | ||
ScheduledJobDto scheduledJobDto3 = pair.Value; | ||
jobs.Add(JobEntity.Parse(id, scheduledJobDto3.Job)); | ||
} | ||
} | ||
|
||
if (!CheckRunningJobs) | ||
{ | ||
return jobs; | ||
} | ||
|
||
foreach (KeyValuePair<string, ProcessingJobDto> pair in | ||
monitoringApi.ProcessingJobs(0, 500)) | ||
{ | ||
string id = pair.Key; | ||
ProcessingJobDto processingJobDto3 = pair.Value; | ||
jobs.Add(JobEntity.Parse(id, processingJobDto3.Job)); | ||
} | ||
|
||
return jobs; | ||
} | ||
|
||
public void OnStateElection(ElectStateContext context) | ||
{ | ||
if (!(context.CandidateState is EnqueuedState candidateState)) | ||
{ | ||
return; | ||
} | ||
|
||
candidateState.Queue = Queue; | ||
BackgroundJob job = context.BackgroundJob; | ||
var filteredArguments = job.Job.Args.Where(x => x.GetType() != typeof(CancellationToken)).ToList(); | ||
var jobArgs = JsonSerializer.Serialize(filteredArguments, | ||
new JsonSerializerOptions() { IncludeFields = false }); | ||
var jobs = GetJobs(context); | ||
var jobsWithArgs = jobs | ||
.Select(x => new { JobEntity = x, ArgAsString = jobArgs }).ToList(); | ||
var alreadyExists = jobsWithArgs.Exists(x => | ||
x.JobEntity.Value.Method == job.Job.Method && x.ArgAsString == jobArgs && x.JobEntity.Id != job.Id); | ||
if (!alreadyExists) | ||
{ | ||
return; | ||
} | ||
|
||
context.CandidateState = | ||
new DeletedState() { Reason = "Instance of the same job is already queued." }; | ||
} | ||
|
||
private sealed record JobEntity(string Id, global::Hangfire.Common.Job Value) | ||
{ | ||
public static JobEntity | ||
Parse(string id, global::Hangfire.Common.Job job) => | ||
new(id, job); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.