Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change Worker Service interval time from external file when service is already installed

I am working on .NET Core 'Worker Service' project to implement service for Windows & Linux OS.

Service reading data from external config.xml file like credentials/urls. I want to add interval time too in config file so that in future if I want change interval time(ex. every hour to every 2 hour), I will just update config file, I not need to modify and recompile the code.

I am using Coraval library for scheduling. Setting interval time in Main method. My doubt is when I will change interval time in config file(being read in Main method), how will it get assigned for further executions? for Windows and Linux.

How often Main method getting called so that it will read new scheduling time from config file?

This is my code

public static void Main(string[] args)
{
    var schedulingConfig = GlobalSettings.ReadIntervals(out List<intervalValue> intervalvalues);
    string intrvaltype = string.Empty;
    foreach (var item in schedulingConfig)
    {
        if (item.Name == "true")
        {
            intrvaltype = item.Execution;
            break;
        }
    }
    IHost host = CreateHostBuilder(args).Build();
    host.Services.UseScheduler(scheduler =>
    {
       //Remind schedular to repeat the same job  
        switch (intrvaltype)
        {
            case "isSignleHourInADay":
                scheduler
               .Schedule<ReprocessInvocable>()
               .Hourly();
                break;
            case "isMinutes":
                scheduler
               .Schedule<ReprocessInvocable>()
               .EveryFiveMinutes();
                break;

            case "isOnceInADay":
                scheduler
               .Schedule<ReprocessInvocable>()
               .Daily();
                break;

            case "isSecond":
                scheduler
               .Schedule<ReprocessInvocable>()
               .EveryThirtySeconds();
                break;
        }  
    });
    host.Run();
}

Where should I keep my code so that it will do the needful?

Edit1

Program.cs class

public class Program
{
    public static void Main(string[] args)
    {
        IHost host = CreateHostBuilder(args).Build();
        host.Services.UseScheduler(scheduler =>
        {
            scheduler
            .Schedule<ReprocessInvocable>()
            .Hourly()
            .When(() => IsRun("isSignleHourInADay"));

            scheduler
            .Schedule<ReprocessInvocable>()
            .EveryFiveMinutes()
            .When(() => IsRun("isMinutes"));

            scheduler
            .Schedule<ReprocessInvocable>()
            .Daily()
            .When(() => IsRun("isOnceInADay"));

            scheduler
            .Schedule<ReprocessInvocable>()
            .EveryThirtySeconds()
            .When(() => IsRun("isSecond"));

        });
        host.Run();
    }
    public static IHostBuilder CreateHostBuilder(string[] args) =>
          Host.CreateDefaultBuilder(args)
              .ConfigureServices(services =>
              {
                  services.AddScheduler();
              }).UseSerilog().UseSystemd();

    static Task<bool> IsRun(string intervalType)
    {
        return Task.Run(() =>
        {
            var schedulingConfig = ConfigData();
            string configIntrvalType = schedulingConfig.FirstOrDefault(i => i.Name == "true")?.Execution;
            return intervalType == configIntrvalType;
        });
    }

    public static List<intervalValue> ConfigData()
    {
        return new List<intervalValue> { new intervalValue { Execution= "isSignleHourInADay", Name="false"},
                                         new intervalValue { Execution= "isMinutes", Name="true"},
                                         new intervalValue { Execution= "isOnceInADay", Name="false"},
                                         new intervalValue { Execution= "isSecond", Name="false"},
                                         new intervalValue { Execution= "isMultipleHoursInADay", Name="false"},
        };
    }
    public class intervalValue
    {
        public string Execution { get; set; }
        public string Name { get; set; }
    }
}

ReprocessInvocable.cs class

public class ReprocessInvocable : IInvocable
{
    private readonly ILogger<ReprocessInvocable> _logger;
    public ReprocessInvocable(ILogger<ReprocessInvocable> logger)
    {
        _logger = logger;
    }
    public async Task Invoke()
    {
        _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
        Log.Information("Invoke has called at: {time}", DateTimeOffset.Now);
    }
}

Edit2 This is StatusConfigTest2.xml file

<?xml version="1.0" encoding="UTF-8"?>
<parameters>  
<intervalValue>
<Definition Execution="isMultipleHoursInADayVal" Name="1AM,4PM,6AM"></Definition>
<Definition Execution="isSignleHourInADayVal" Name="4AM"></Definition>
<Definition Execution="isMinutesVal" Name="5"></Definition>
<Definition Execution="isOnceInADayVal" Name="5PM"></Definition>
<Definition Execution="isSecondVal" Name="20"></Definition>
</intervalValue>
<intervalType>
<Definition Execution="isMultipleHoursInADay" Name="false"></Definition>
<Definition Execution="isSignleHourInADay" Name="false"></Definition>
<Definition Execution="isMinutes" Name="true"></Definition>
<Definition Execution="isOnceInADay" Name="false"></Definition>
<Definition Execution="isSecond" Name="false"></Definition>
</intervalType>
</parameters>

Method to read xml file

public static List<intervalValue> GetFilterProducts1(out List<intervalValue> 
intervalValueout)
{
    List<intervalValue> IntrvalValueList = new List<intervalValue>();
    List<intervalValue> IntervalTypeList = new List<intervalValue>();

    try
    {
        FileStream fs = null;
        var files = new List<string>();
        files.Add("D:/ProductStatusConfigTest2.xml");
        //file2
        //file3
        foreach (var file in files)
        {
            try
            {
                fs = new FileStream(file, FileMode.Open, FileAccess.Read);
                break;
            }
            catch (Exception ex)
            {
                //throw;
            }
        }

        XmlDocument doc = new XmlDocument();
        doc.Load(fs);
        XmlNode node = doc.DocumentElement.SelectSingleNode("/parameters/intervalValue");
        {
            for (int i = 0; i < node.ChildNodes.Count; i++)
            {
                IntrvalValueList.Add(new intervalValue { Name = node.ChildNodes[i].Attributes["Name"].Value, Execution = node.ChildNodes[i].Attributes["Execution"].Value });
            }
        }
        XmlNode node2 = doc.DocumentElement.SelectSingleNode("/parameters/intervalType");
        {
            for (int i = 0; i < node.ChildNodes.Count; i++)
            {
                IntervalTypeList.Add(new intervalValue { Name = node2.ChildNodes[i].Attributes["Name"].Value, Execution = node2.ChildNodes[i].Attributes["Execution"].Value });
            }
        }
        intervalValueout = IntrvalValueList;
        return IntervalTypeList;
    }
    catch (Exception ex)
    {
        intervalValueout = IntervalTypeList;
        return IntervalTypeList;
    }
}
like image 233
R15 Avatar asked Oct 30 '25 14:10

R15


1 Answers

As I saw in Coravel, it has When method that could be your solution:

First define a method that say which Interval is valid to run based on your config:

static Task<bool> IsRun(string intervalType)
{
    return Task.Run(() =>
    {
        var schedulingConfig = GlobalSettings.ReadIntervals(out List<intervalValue> intervalvalues);
        string configIntrvalType = schedulingConfig.FirstOrDefault(i => i.Name == "true")?.Execution;
        return intervalType == configIntrvalType;
    });
}

Then add When to your Invocables this way:

host.Services.UseScheduler(scheduler =>
{
    scheduler
    .Schedule<ReprocessInvocable>()
    .Hourly()
    .When(() => IsRun("isSignleHourInADay"));

    scheduler
    .Schedule<ReprocessInvocable>()
    .EveryFiveMinutes()
    .When(() => IsRun("isMinutes"));

    scheduler
    .Schedule<ReprocessInvocable>()
    .Daily()
    .When(() => IsRun("isOnceInADay"));

    scheduler
    .Schedule<ReprocessInvocable>()
    .EveryThirtySeconds()
    .When(() => IsRun("isSecond"));
});

Edit

Here's full code that should work:

Program.cs

public class Program
{
    public static void Main(string[] args)
    {
        IHost host = CreateHostBuilder(args).Build();
        host.Services.UseScheduler(scheduler =>
        {
            scheduler
            .Schedule<ReprocessInvocable>()
            .Hourly()
            .When(() => IsRun("isSignleHourInADay"));

            scheduler
            .Schedule<ReprocessInvocable>()
            .EveryMinute()
            .When(() => IsRun("isMinutes"));

            scheduler
            .Schedule<ReprocessInvocable>()
            .Daily()
            .When(() => IsRun("isOnceInADay"));

            scheduler
            .Schedule<ReprocessInvocable>()
            .EverySecond()
            .When(() => IsRun("isSecond"));

        });
        host.Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureServices((hostContext, services) =>
            {
                services.AddScoped<ReprocessInvocable>();
                services.AddScheduler();
            });

    static Task<bool> IsRun(string intervalType)
    {
        return Task.Run(() =>
        {
            var schedulingConfig = GetFilterProducts(out List<intervalValue> intrvalValueList);
            string configIntrvalType = schedulingConfig.FirstOrDefault(i => i.Name.ToLower().Trim() == "true")?.Execution;
            return intervalType.ToLower().Trim() == configIntrvalType.ToLower().Trim();
        });
    }

    static List<intervalValue> GetFilterProducts(out List<intervalValue> intervalValueList)
    {
        List<intervalValue> IntervalTypeList = new List<intervalValue>();
        intervalValueList = new List<intervalValue>();

        try
        {
            XmlDocument doc = new XmlDocument();
            doc.Load("D:/ProductStatusConfigTest2.xml");
            XmlNode node = doc.DocumentElement.SelectSingleNode("/parameters/intervalValue");
            {
                for (int i = 0; i < node.ChildNodes.Count; i++)
                {
                    intervalValueList.Add(new intervalValue { Name = node.ChildNodes[i].Attributes["Name"].Value, Execution = node.ChildNodes[i].Attributes["Execution"].Value });
                }
            }
            XmlNode node2 = doc.DocumentElement.SelectSingleNode("/parameters/intervalType");
            {
                for (int i = 0; i < node.ChildNodes.Count; i++)
                {
                    IntervalTypeList.Add(new intervalValue { Name = node2.ChildNodes[i].Attributes["Name"].Value, Execution = node2.ChildNodes[i].Attributes["Execution"].Value });
                }
            }
            return IntervalTypeList;
        }
        catch (Exception ex)
        {
            intervalValueList = IntervalTypeList;
            return IntervalTypeList;
        }
    }

    class intervalValue
    {
        public string Execution { get; set; }
        public string Name { get; set; }
    }
}

ReprocessInvocable.cs

public class ReprocessInvocable : IInvocable
{
    private readonly ILogger<ReprocessInvocable> _logger;
    public ReprocessInvocable(ILogger<ReprocessInvocable> logger)
    {
        _logger = logger;
    }
    public async Task Invoke()
    {
        _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
        await Task.CompletedTask;
    }
}
like image 138
Arman Ebrahimpour Avatar answered Nov 01 '25 04:11

Arman Ebrahimpour



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!