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;
}
}
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;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With