I have developed web job project which is having multiple timer trigger functions. Each function is executed at different time of the day. Some of them are executed every minute ,some every five minute and some of them once in a day.
If I write the CRON expression in the function parameter attribute itself like
ProcessTrigger2([TimerTrigger("0 */3 * * * *", RunOnStartup = false)]TimerInfo timerInfo)
, it works as expected but when I try it to read from appsettings.json it fails.
Could anyone suggest the right way of reading the appsettings.json in Functions.cs ??
Following is the code that I am trying.
Program.cs
internal class Program
{
// Please set the following connection strings in app.config for this WebJob to run:
// AzureWebJobsDashboard and AzureWebJobsStorage
private static void Main()
{
ServiceCollection services = new ServiceCollection();
ConfigureServices(services);
var config = new JobHostConfiguration();
config.JobActivator = new JobActivator(services.BuildServiceProvider());
config.UseTimers();
if (config.IsDevelopment)
{
config.UseDevelopmentSettings();
}
var host = new JobHost(config);
// The following code ensures that the WebJob will be running continuously
host.RunAndBlock();
}
private static IConfiguration Configuration { get; set; }
private static void ConfigureServices(IServiceCollection services)
{
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
Configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{environment}.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
services.AddSingleton(Configuration);
services.AddTransient<Functions, Functions>();
services.AddLogging(builder => builder.AddConsole());
}
}
Functions.cs
public class Functions
{
private readonly ILogger<Functions> logger;
private readonly IConfiguration configuration;
public Functions(ILogger<Functions> logger, IConfiguration configuration)
{
this.configuration = configuration;
this.logger = logger;
}
[FunctionName("TimerTriggerEveryMinute")]
public void ProcessTrigger1([TimerTrigger("%TimerTriggerEveryMinute:Schedule%")]TimerInfo timerInfo)
{
var ab = this.configuration;
Console.WriteLine(string.Format("{0} Proc 1",DateTime.Now));
}
[FunctionName("TimerTriggerEveryThirdMinute")]
public void ProcessTrigger2([TimerTrigger("0 */3 * * * *", RunOnStartup = false)]TimerInfo timerInfo)
{
Console.WriteLine(string.Format("{0} Proc 2",DateTime.Now));
}
[FunctionName("TimerTriggerEveryFiveMinute")]
public void ProcessTrigger3([TimerTrigger("%EveryFiveMinuteSchedule%",RunOnStartup =false)]TimerInfo timer)
{
Console.WriteLine(string.Format("{0} Proc 5", DateTime.Now));
}
}
JobActivator.cs
public class JobActivator : IJobActivator
{
private readonly IServiceProvider services;
public JobActivator(IServiceProvider services)
{
this.services = services;
}
public T CreateInstance<T>()
{
return services.GetService<T>();
}
}
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"ConnectionStrings": {
"AzureWebJobsDashboard": "My Azure Dashboard key here...",
"AzureWebJobsStorage": "My Azure Job Storage key here...",
},
"TimerTriggerEveryMinute": {
"Schedule": "0 * * * * *"
},
"TimerTriggerEveryFiveMinute": {
"Schedule": "0 */5 * * * *"
}
}
In above code, in Functions.cs, if I write the timer trigger in
ProcessTrigger2([TimerTrigger("0 */3 * * * *", RunOnStartup = false)]TimerInfo timerInfo)
this manner for all methods, the job works as expected but if I write in other two manners it gives me the exception.
Please suggest the write way of reading the schedule from appsettings.json.
Yes. Instead of hard-coding a CRON expression, put the expression in an app setting and refer to it using %
signs. For instance, if you have a setting called CRON_EXPRESSION
:
public static void Run([TimerTrigger("%CRON_EXPRESSION%")]TimerInfo myTimer, TraceWriter log)
Refer - https://github.com/Azure/azure-functions-host/issues/1934