From 534e1e667918fd6c4f1fabaf01288a95ef11e622 Mon Sep 17 00:00:00 2001 From: kuberto773 Date: Mon, 23 Feb 2026 13:15:40 +0100 Subject: [PATCH 1/3] chore: upgrade Hangfire lib --- .../Madev.Utils.Infrastructure.Hangfire.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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..4e5a7ed 100644 --- a/src/Madev.Utils.Infrastructure.Hangfire/Madev.Utils.Infrastructure.Hangfire.csproj +++ b/src/Madev.Utils.Infrastructure.Hangfire/Madev.Utils.Infrastructure.Hangfire.csproj @@ -15,7 +15,7 @@ - + From 6253a1f9e7ea9f7048be5fd6a39598b63300b26e Mon Sep 17 00:00:00 2001 From: kuberto773 Date: Mon, 23 Feb 2026 13:16:10 +0100 Subject: [PATCH 2/3] chore: upgrade Hangfire utils to dotnet 10 --- .../Madev.Utils.Infrastructure.Hangfire.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 4e5a7ed..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 From ca005c723be041fcf2bc6c14814d0d13c6dfea56 Mon Sep 17 00:00:00 2001 From: kuberto773 Date: Mon, 23 Feb 2026 13:17:54 +0100 Subject: [PATCH 3/3] feat: Hangfire attribute for allowed execution time --- .../AllowedExecutionTimeRangeAttribute.cs | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 src/Madev.Utils.Infrastructure.Hangfire/Attributes/AllowedExecutionTimeRangeAttribute.cs 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; + } +}