Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,73 +1,76 @@
using System.Globalization;
using System;
using System.Globalization;
using Hangfire.Common;
using Hangfire.States;

namespace Madev.Utils.Infrastructure.Hangfire.Attributes;

public class AllowedExecutionTimeRangeAttribute : JobFilterAttribute, IElectStateFilter
namespace Madev.Utils.Infrastructure.Hangfire.Attributes
{
private readonly TimeSpan _timeFrom;
private readonly TimeSpan _timeTo;

/// <summary>
/// Allows to run tasks only at a time interval
/// </summary>
/// <param name="timeFrom">Time from (HH:mm:ss)</param>
/// <param name="timeTo">Time to (HH:mm:ss)</param>
public AllowedExecutionTimeRangeAttribute(string timeFrom, string timeTo)
public class AllowedExecutionTimeRangeAttribute : JobFilterAttribute, IElectStateFilter
{
_timeFrom = DateTime.ParseExact(timeFrom, "HH:mm:ss", CultureInfo.InvariantCulture).TimeOfDay;
_timeTo = DateTime.ParseExact(timeTo, "HH:mm:ss", CultureInfo.InvariantCulture).TimeOfDay;
}
private readonly TimeSpan _timeFrom;
private readonly TimeSpan _timeTo;

public void OnStateElection(ElectStateContext context)
{
if (context.CurrentState != EnqueuedState.StateName) return;
/// <summary>
/// Allows to run tasks only at a time interval
/// </summary>
/// <param name="timeFrom">Time from (HH:mm:ss)</param>
/// <param name="timeTo">Time to (HH:mm:ss)</param>
public AllowedExecutionTimeRangeAttribute(string timeFrom, string timeTo)
{
_timeFrom = DateTime.ParseExact(timeFrom, "HH:mm:ss", CultureInfo.InvariantCulture).TimeOfDay;
_timeTo = DateTime.ParseExact(timeTo, "HH:mm:ss", CultureInfo.InvariantCulture).TimeOfDay;
}

var state = context.Connection.GetStateData(context.BackgroundJob.Id);
if (state == null) return; // just in case
public void OnStateElection(ElectStateContext context)
{
if (context.CurrentState != EnqueuedState.StateName) return;

var dateTimeNow = GetTimeInCentralEuropeStandardTime(DateTime.Now);
var state = context.Connection.GetStateData(context.BackgroundJob.Id);
if (state == null) return; // just in case

if (JobIsAllowedInActualTime(dateTimeNow) == false)
{
context.CandidateState = new FailedState(new ArgumentOutOfRangeException($"It is not allowed to perform the task at {dateTimeNow}"))
var dateTimeNow = GetTimeInCentralEuropeStandardTime(DateTime.Now);

if (JobIsAllowedInActualTime(dateTimeNow) == false)
{
Reason = $"It is not allowed to perform the task at {dateTimeNow}"
};
context.CandidateState = new FailedState(new ArgumentOutOfRangeException($"It is not allowed to perform the task at {dateTimeNow}"))
{
Reason = $"It is not allowed to perform the task at {dateTimeNow}"
};
}
}
}

public bool JobIsAllowedInActualTime(TimeSpan now)
{
if (_timeFrom == _timeTo)
throw new Exception("Duration cannot be 0h0m0s");

// if range is over midnight (from: 23:00:00 to: 01:00:00 duration: 2h)
if (_timeFrom > _timeTo)
public bool JobIsAllowedInActualTime(TimeSpan now)
{
if ((now >= _timeFrom) || (now <= _timeTo))
if (_timeFrom == _timeTo)
throw new Exception("Duration cannot be 0h0m0s");

// if range is over midnight (from: 23:00:00 to: 01:00:00 duration: 2h)
if (_timeFrom > _timeTo)
{
return true;
if ((now >= _timeFrom) || (now <= _timeTo))
{
return true;
}
}
}

// if range is over day (from: 01:00:00 to: 23:00:00 duration: 22h)
if (_timeFrom < _timeTo)
{
if ((now >= _timeFrom) && (now <= _timeTo))
// if range is over day (from: 01:00:00 to: 23:00:00 duration: 22h)
if (_timeFrom < _timeTo)
{
return true;
if ((now >= _timeFrom) && (now <= _timeTo))
{
return true;
}
}
}

return false;
}
return false;
}

public TimeSpan GetTimeInCentralEuropeStandardTime(DateTime dateTime)
{
TimeZoneInfo infotime = TimeZoneInfo.FindSystemTimeZoneById("Central Europe Standard Time");
public TimeSpan GetTimeInCentralEuropeStandardTime(DateTime dateTime)
{
TimeZoneInfo infotime = TimeZoneInfo.FindSystemTimeZoneById("Central Europe Standard Time");

return TimeZoneInfo.ConvertTimeBySystemTimeZoneId(dateTime, infotime.Id).TimeOfDay;
return TimeZoneInfo.ConvertTimeBySystemTimeZoneId(dateTime, infotime.Id).TimeOfDay;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,40 +1,44 @@
using Hangfire.Common;
using Hangfire.States;
using Hangfire.Storage;
using System;
using System.Linq;

namespace Madev.Utils.Infrastructure.Hangfire.Attributes;
public sealed class DisableMultipleQueuedItemsFilterAttribute : JobFilterAttribute, IElectStateFilter
namespace Madev.Utils.Infrastructure.Hangfire.Attributes
{
private readonly string _jobName;

public DisableMultipleQueuedItemsFilterAttribute(string jobName)
public sealed class DisableMultipleQueuedItemsFilterAttribute : JobFilterAttribute, IElectStateFilter
{
_jobName = jobName;
}
private readonly string _jobName;

public void OnStateElection(ElectStateContext context)
{
var monitoring = context.Storage.GetMonitoringApi();
public DisableMultipleQueuedItemsFilterAttribute(string jobName)
{
_jobName = jobName;
}

if (ActiveProcess(monitoring) && !context.CandidateState.IsFinal && context.CandidateState.Name != FailedState.StateName && context.CurrentState != ScheduledState.StateName)
public void OnStateElection(ElectStateContext context)
{
context.CandidateState = new DeletedState
var monitoring = context.Storage.GetMonitoringApi();

if (ActiveProcess(monitoring) && !context.CandidateState.IsFinal && context.CandidateState.Name != FailedState.StateName && context.CurrentState != ScheduledState.StateName)
{
Reason = $"It is not allowed to perform multiple same tasks: {_jobName}"
};
context.CandidateState = new DeletedState
{
Reason = $"It is not allowed to perform multiple same tasks: {_jobName}"
};
}
}
}

private bool ActiveProcess(IMonitoringApi monitoring)
{
var processingJobs = monitoring.ProcessingJobs(0, 2000);
var scheduledJobs = monitoring.ScheduledJobs(0, 2000);
private bool ActiveProcess(IMonitoringApi monitoring)
{
var processingJobs = monitoring.ProcessingJobs(0, 2000);
var scheduledJobs = monitoring.ScheduledJobs(0, 2000);

var hasProcessingJob = processingJobs.Where(x =>
x.Value.Job.Type.Name.Equals(_jobName, StringComparison.InvariantCultureIgnoreCase));
var hasScheduledJob = scheduledJobs.Where(x =>
x.Value.Job.Type.Name.Equals(_jobName, StringComparison.InvariantCultureIgnoreCase));
var hasProcessingJob = processingJobs.Where(x =>
x.Value.Job.Type.Name.Equals(_jobName, StringComparison.InvariantCultureIgnoreCase));
var hasScheduledJob = scheduledJobs.Where(x =>
x.Value.Job.Type.Name.Equals(_jobName, StringComparison.InvariantCultureIgnoreCase));

return hasProcessingJob.Count() + hasScheduledJob.Count() > 0;
return hasProcessingJob.Count() + hasScheduledJob.Count() > 0;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<TargetFrameworks>netstandard2.1;net10.0</TargetFrameworks>
<Nullable>enable</Nullable>

<Authors>Miroslav Adamec</Authors>
<Company>Madev</Company>
<Description>Hangfire background job scheduler etilities and extensions</Description>
<Description>Hangfire background job scheduler utilities and extensions</Description>
<PackageProjectUrl>https://github.com/madev/Madev.Utils</PackageProjectUrl>
<RepositoryUrl>https://github.com/madev/Madev.Utils</RepositoryUrl>
<PackageTags>mirecad madev hangfire tools utils extensions</PackageTags>
Expand Down
Loading