Skip to content

Instantly share code, notes, and snippets.

@Gh61
Last active March 5, 2025 15:57
Show Gist options
  • Save Gh61/2cac20b443f29c53259f2d6cd0d0af64 to your computer and use it in GitHub Desktop.
Save Gh61/2cac20b443f29c53259f2d6cd0d0af64 to your computer and use it in GitHub Desktop.
An attribute that prevents processing a Hangfire job that is part of recurring job currently in the Retry state.
/// <summary>
/// An attribute that prevents processing a Hangfire job that is part of recurring job currently in the Retry state.
/// </summary>
/// <remarks>
/// This attribute is intended for recurring tasks only. If used on any other type of task, an exception will be thrown.
/// </remarks>
public class SkipRetryingRecurrentJobAttribute : JobFilterAttribute, IServerFilter
{
private const string recurringJobId = "RecurringJobId";
public void OnPerforming(PerformingContext context)
{
var recurringName = context.GetJobParameter<string>("RecurringJobId");
if (string.IsNullOrEmpty(recurringName))
{
throw new InvalidOperationException(nameof(SkipConcurrentTaskExecutionAttribute) + " can be used only for recurring jobs.");
}
if (!(context.Connection is JobStorageConnection storage))
{
throw new InvalidOperationException($"Only {nameof(JobStorageConnection)} is supported.");
}
var retryJobIds = storage.GetAllItemsFromSet("retries");
foreach (var retryJobId in retryJobIds)
{
// never resolve current job
if (retryJobId == context.BackgroundJob.Id)
continue;
// get the name of reccuring job from the retry job Id
var retryJobRecurringName = DeserializeJobParameterString(storage.GetJobParameter(retryJobId, recurringJobId));
// if we're trying to start new job with the same recurring name as in retry set, cancel the run
if (retryJobRecurringName == recurringName)
{
context.Canceled = true;
}
}
}
public void OnPerformed(PerformedContext context)
{
}
private static string DeserializeJobParameterString(string value)
{
if (string.IsNullOrEmpty(value))
return value;
// if it starts and ends with quotes, get rid of them
if (value.StartsWith("\"") && value.EndsWith("\""))
{
return value.Substring(1, value.Length - 2);
}
// nothing here
return value;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment