Last active
June 18, 2024 21:25
-
-
Save odinserj/a6ad7ba6686076c9b9b2e03fcf6bf74e to your computer and use it in GitHub Desktop.
SkipWhenPreviousJobIsRunningAttribute.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
// Zero-Clause BSD (more permissive than MIT, doesn't require copyright notice) | |
// | |
// Permission to use, copy, modify, and/or distribute this software for any purpose | |
// with or without fee is hereby granted. | |
// | |
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | |
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, | |
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS | |
// OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | |
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
// THIS SOFTWARE. | |
using System; | |
using System.Collections.Generic; | |
using Hangfire.Client; | |
using Hangfire.Common; | |
using Hangfire.States; | |
using Hangfire.Storage; | |
namespace ConsoleApp28 | |
{ | |
public class SkipWhenPreviousJobIsRunningAttribute : JobFilterAttribute, IClientFilter, IApplyStateFilter | |
{ | |
public void OnCreating(CreatingContext context) | |
{ | |
var connection = context.Connection as JobStorageConnection; | |
// We can't handle old storages | |
if (connection == null) return; | |
// We should run this filter only for background jobs based on | |
// recurring ones | |
if (!context.Parameters.ContainsKey("RecurringJobId")) return; | |
var recurringJobId = context.Parameters["RecurringJobId"] as string; | |
// RecurringJobId is malformed. This should not happen, but anyway. | |
if (String.IsNullOrWhiteSpace(recurringJobId)) return; | |
var running = connection.GetValueFromHash($"recurring-job:{recurringJobId}", "Running"); | |
if ("yes".Equals(running, StringComparison.OrdinalIgnoreCase)) | |
{ | |
context.Canceled = true; | |
} | |
} | |
public void OnCreated(CreatedContext filterContext) | |
{ | |
} | |
public void OnStateApplied(ApplyStateContext context, IWriteOnlyTransaction transaction) | |
{ | |
if (context.NewState is EnqueuedState) | |
{ | |
var recurringJobId = JobHelper.FromJson<string>(context.Connection.GetJobParameter(context.BackgroundJob.Id, "RecurringJobId")); | |
if (String.IsNullOrWhiteSpace(recurringJobId)) return; | |
transaction.SetRangeInHash( | |
$"recurring-job:{recurringJobId}", | |
new[] { new KeyValuePair<string, string>("Running", "yes") }); | |
} | |
else if ((context.NewState.IsFinal && !FailedState.StateName.Equals(context.OldStateName, StringComparison.OrdinalIgnoreCase)) || | |
(context.NewState is FailedState)) | |
{ | |
var recurringJobId = JobHelper.FromJson<string>(context.Connection.GetJobParameter(context.BackgroundJob.Id, "RecurringJobId")); | |
if (String.IsNullOrWhiteSpace(recurringJobId)) return; | |
transaction.SetRangeInHash( | |
$"recurring-job:{recurringJobId}", | |
new []{ new KeyValuePair<string, string>("Running", "no") }); | |
} | |
} | |
public void OnStateUnapplied(ApplyStateContext context, IWriteOnlyTransaction transaction) | |
{ | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
If you have this issue here is the solution for it.
After investigation, I found out that our customer
SkipWhenPreviousJobIsRunningAttribute
will triggerOnStateApplied
method after the job has been deleted.The reason why it is doing that is this scenario :
The job will be triggered for running, during the running time and still not completed we delete the job!
On time the job is completed method OnStateApplied will be triggered even if the job is deleted and it will create a new row in the table hash.
If we want to keep the custom attribute
SkipWhenPreviousJobIsRunningAttribute
Before adding the new row to
hash
table check if the job is deleted or notThe benefit of this approach is that it will save us of creating unneeded data in the DB.
Unfortunately, it will increase the load on the DB since it is one more additional request.