diff --git a/src/Madev.Utils.Infrastructure.Hangfire/Attributes/AllowedExecutionTimeRangeAttribute.cs b/src/Madev.Utils.Infrastructure.Hangfire/Attributes/AllowedExecutionTimeRangeAttribute.cs new file mode 100644 index 0000000..99943d0 --- /dev/null +++ b/src/Madev.Utils.Infrastructure.Hangfire/Attributes/AllowedExecutionTimeRangeAttribute.cs @@ -0,0 +1,73 @@ +using System.Globalization; +using Hangfire.Common; +using Hangfire.States; + +namespace Madev.Utils.Infrastructure.Hangfire.Attributes; + +public class AllowedExecutionTimeRangeAttribute : JobFilterAttribute, IElectStateFilter +{ + private readonly TimeSpan _timeFrom; + private readonly TimeSpan _timeTo; + + /// + /// Allows to run tasks only at a time interval + /// + /// Time from (HH:mm:ss) + /// Time to (HH:mm:ss) + 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; + } + + public void OnStateElection(ElectStateContext context) + { + if (context.CurrentState != EnqueuedState.StateName) return; + + var state = context.Connection.GetStateData(context.BackgroundJob.Id); + if (state == null) return; // just in case + + var dateTimeNow = GetTimeInCentralEuropeStandardTime(DateTime.Now); + + if (JobIsAllowedInActualTime(dateTimeNow) == false) + { + 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) + { + 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)) + { + return true; + } + } + + return false; + } + + public TimeSpan GetTimeInCentralEuropeStandardTime(DateTime dateTime) + { + TimeZoneInfo infotime = TimeZoneInfo.FindSystemTimeZoneById("Central Europe Standard Time"); + + return TimeZoneInfo.ConvertTimeBySystemTimeZoneId(dateTime, infotime.Id).TimeOfDay; + } +} diff --git a/src/Madev.Utils.Infrastructure.Hangfire/Madev.Utils.Infrastructure.Hangfire.csproj b/src/Madev.Utils.Infrastructure.Hangfire/Madev.Utils.Infrastructure.Hangfire.csproj index 2507702..135f57a 100644 --- a/src/Madev.Utils.Infrastructure.Hangfire/Madev.Utils.Infrastructure.Hangfire.csproj +++ b/src/Madev.Utils.Infrastructure.Hangfire/Madev.Utils.Infrastructure.Hangfire.csproj @@ -1,7 +1,7 @@  - net9.0 + net10.0 enable enable @@ -15,7 +15,7 @@ - +