azure Webjob TimerTrigger, force scheduling - c#

I have an azure webjob TimerTrigger.
We may be led to stop the webjob, in a way or another (for instance changing an appSetting, aborts the webjob).
The webjob is defined as TimerTrigger in Azure. There are storage accounts for AzureWebJobsDashboard and AzureWebJobsStorage in the appSettings of the webjob. The webjob is executed at a certain time of the day. The execution of the webjob may last 5 or 6 hours. there are massive writings in a storage account (around 13000) and in storage table.
The question is :
When restarting the webjob, there is, often, an UnscheduledInvocationReason: IsPastDue, OriginalSchedule. I would like to avoid that, that the next execution of the webjob will be done accordingly to the cron expression of the timerTrigger webjob.
Is it possible, and if so how to do that ?
Any idea ?
Regards.

If I understand the problem correctly, you could use RunOnStartup = false (default) and UseMonitor = false
Timer trigger for Azure Functions
Parameter
Description
RunOnStartup
If true, the function is invoked when the runtime starts. For example, the runtime starts when the function app wakes up after going idle due to inactivity. when the function app restarts due to function changes, and when the function app scales out. So runOnStartup should rarely if ever be set to true, especially in production.
UseMonitor
Set to true or false to indicate whether the schedule should be monitored. Schedule monitoring persists schedule occurrences to aid in ensuring the schedule is maintained correctly even when function app instances restart. If not set explicitly, the default is true for schedules that have a recurrence interval greater than or equal to 1 minute. For schedules that trigger more than once per minute, the default is false.
There are a few ways to set these values, however it can be set from the attribute it self
[FunctionName("MyLovelyHorseFunction")]
public static void Run(
[TimerTrigger(
"0 */5 * * * *",
RunOnStartup = false,
UseMonitor = false)]
TimerInfo myTimer,
ILogger log)
{
...
}
Also note, you can explicitly check for past due (which may or may not help you out depending on your needs)
if (myTimer.IsPastDue)
{
...
}

Related

How to renew Service Bus message from Azure Function?

I follow Microsoft's document to setup (using c#) but message will be expired due to Service Bus queue’s lock duration.
isSessionsEnabled is false, my setting in `host.json is as below for reference:
{
"version": "2.0",
"functionTimeout": "00:10:00",
"extensions": {
"serviceBus": {
"prefetchCount": 100,
"messageHandlerOptions": {
"autoComplete": true,
"maxConcurrentCalls": 32,
// tried "00:00:55", "00:02:30", "00:05:00"
"maxAutoRenewDuration": "00:10:00"
}
}
}
}
I also tried to not implement extensions in host.json (as from document it will auto-renew the lock) but still does not work.
For reference, found this mentioned that Microsoft's document may have something wrong but did not mention possible solutions.
There is no need to renew the lock manually as its control by the run time of function.
Function can renew the message lock by itself.
If you have set isSessionsEnabled to true, the sessionHandlerOptions will honored. As you have set isSessionsEnabled to false, then messageHandlerOptions will honored.
The Peeklock behavior :
When Functions runtime receieve a message in peek-lock mode
it will call Complete on the message once the function finishes
successfully, or calls Abandon if the function fails. If the
function runs longer than the PeekLock timeout, the lock is
automatically renewed as long as the function is running.
The maxAutoRenewDuration is configurable in host.json, which
maps to OnMessageOptions.MaxAutoRenewDuration
Based on the documentation maximum allowed time is 5 minute
whereas you can increase the Functions run time
limit from the default of 5 minutes to 10 minutes. For Service Bus
functions you wouldn’t want to do that, because you’d exceed the
Service Bus renewal limit.
Please refer this for further information about Message expiration .
Can you share the signature of your function? I believe maxAutoRenewDuration only applies for functions receiving a single message, i.e. won't work for functions receiving an array/list of messages.

ASPBoilerplate BackgroundJobs database pooling

I am using ABP framework to develop a web application. By default, the default background job manager pools the database every five seconds to find possible existing defined jobs. According to ABP documents and its implementation I find that it's set to five seconds by default. However, I am not able to update the timer to update this. Even if I tried to disable it using the code below, it was unsuccessful and it is still running.
if (DebugHelper.IsDebug)
{
Configuration.BackgroundJobs.IsJobExecutionEnabled = false;
}
To continue, is there a way to replace this background job to quartz only. I think in the case of adding Quartz integration, they both run concurrently.
Any help will be appreciated.
According to its implementation the default value has been set to five seconds and this can be configured and overridden at the PreInitialize method of the CoreModule. All it needs is below:
public override void PreInitialize()
{
...
BackgroundJobManager.JobPollPeriod = 20000; //20 seconds
...
}

Running an azure function on a specific time for only once?

So I'm working on sending mobile app push notifications and I've already set up Azure Notification hub, but I wanted to do scheduling in it, I understand there's an option in build in azure to do that, since it costs 200$ i decided to create Azure Functions to handle it,
I've gone through the NCRON Expressions, now I wanted to know how to schedule a job to run once on a specific date, all I could find is repetition based ones and also is it possible to run a job dynamically as in the date would vary
public static class Function1
{
[FunctionName("Function1")]
public static void Run([TimerTrigger("0 0 15 2 Jan")]TimerInfo myTimer, ILogger log)
{
log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
}
}
I was trying to do something like this, running something on 2nd of Jan at 15:00Hrs, it doesn't seem to work, am I missing something here and how do I make TimerTrigger dynamic?
To describe clearly, I reedit the whole answer. Hope this time I can explain clearly.
OK. Fist of all, you need to know, azure Function has a declaration section and a configuration section.
On local, the declaration section is ([TimerTrigger("* * * * * *")]TimerInfo myTimer, ILogger log), and the configuration section is local.settings.json file.
When you deploy to Azure. It changes. Declaration section turns to function.json, and the Application Settings becomes the configuration section.
To your requirement, you can add a key in the configuration section and get it in your function.
For example,
On local:
function.cs:
using System;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Extensions.Logging;
namespace TimeTrigger
{
public static class Function1
{
[FunctionName("Function1")]
public static void Run([TimerTrigger("%Schedule%")]TimerInfo myTimer, ILogger log)
{
log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
}
}
}
local.settings.json:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"Schedule": "* * * * * *"
}
}
You can change how the timetrigger is triggered by changing the value of the key in the json.(For example, using powershell to modify the value. Or you can use code to modify.)
On portal:
And similar as on local, you can do this on portal:
Declaration section:
Configuration Section:
You can generate the detailed CRON expression using below link:
http://corntab.com/?c=0_15_2_1_*
0 0 15 2 Jan * is the resulting CRON expression which will run it every 2nd day of January at 1500 hours for any years.
As rightly suggested by #Bowman, please check and validate the expression from above link and see if it helps.
Firstly the main problem you have now suppose is your expression, the right expression format you could refer to the doc:NCRONTAB expressions.
{second} {minute} {hour} {day} {month} {day-of-week}
Then about your requirement about run a job dynamically. You can put the schedule expression in an app setting and set this property to the app setting name wrapped in % signs, as in this example: %ScheduleAppSetting%. You could check it in the configuration.
Even with this expression it will show an error, however it will still works.
Why using a timer function if you need to run it only once?
I would say a better solution is to send a message to a queue so it runs at a scheduled time using the attribute ScheduledEnqueueTimeUtc.
https://learn.microsoft.com/en-us/azure/service-bus-messaging/message-sequencing#scheduled-messages

Create a trigger to run a long time executed function C#

I have a function that supposes to run every night at 12 AM and to do some job
usually it takes 2 hours...
I want to create a trigger that calls it.
so I created an Azure function app with time trigger that calls with HTTP request to my controller that calls my function.
the controller function I created just for test.
[HttpGet]
public async Task<bool> updateFromRegAdmin()
{
try
{
RegEditApi_Service.retrieveRegAdminApiCredentials();
return true;
}
catch (Exception e)
{
Logger.writeToLog(Logger.LOG_SEVERITY_TYPE.Error, "", "updateFromRegAdmin ", e.Message);
return false;
}
}
so as I said the function "retrieveRegAdminApiCredentials" runs 2 hours.
and the problem is the request comes to timeout after a few minutes...
so how can I create a request that just triggers the inner function and let it run in the background?
by the way, I can't create a trigger on the server without an HTTP request because my company has scaled servers on Azure(it will run my trigger multiple time and create DB duplicates).
my previous solution to that was...
public class JobScheduler
{
public static void Start()
{
IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler();
scheduler.Start();
IJobDetail job = JobBuilder.Create<GetExchangeRates>().Build();
ITrigger trigger = TriggerBuilder.Create()
.WithDailyTimeIntervalSchedule
(s =>
s.WithIntervalInHours(24)
.OnEveryDay()
.StartingDailyAt(TimeOfDay.HourAndMinuteOfDay(00, 00))
)
.Build();
scheduler.ScheduleJob(job, trigger);
}
}
public class GetExchangeRates : IJob
{
public void Execute(IJobExecutionContext context)
{
Random random = new Random();
int randomNumber = random.Next(100000, 900000);
Thread.Sleep(randomNumber);
RegEditApi_Service.retrieveRegAdminApiCredentials();
}
}
If I understand you correctly, what you have is an Azure Function Timer trigger, that sends an HTTP request to your server with "RegEditApi_Service.retrieveRegAdminApiCredentials()".
The problem is, your function times out. To solve this, you should have the HTTP endpoint behind "retrieveRegAdminApiCredentials()", return immediately on accepting the request.
If you need some return value from the server, you should have the server put a message on some queue ( like Azure Storage queue) and have another Azure Function that listens to this queue, and accepts the message.
If the result of the long operation is relatively small, you can just have the result in the message. Otherwise, you would need to perform some operation, but this operation should be much quicker, because you have already performed the long running operation, and kept the answer, so now you will just retrieve it, and possibly do some cleanup.
You can also look into Azure Durable Functions, it is intended for this use case, but is still in preview, and I'm not sure how much benefit it will give you :
https://learn.microsoft.com/en-us/azure/azure-functions/durable-functions-overview#pattern-3-async-http-apis
Looks like you need a dedicated component able to schedule and execute a queue of tasks. There are nice frameworks for that, but if you dislike those for whatever reason, then make sure you initiate/reuse idle thread and force long execution there. As such, your API will return something alike: 200, OK meaning that process has started successfuly.
Key idea: distinct your threads explicitly. That's actually quite challenging.
Azure functions by default run to a maximum of 15 minutes (maybe 5, too lazy to check the documentation right now :-) ).
If your function is on a Consumption Plan, you can't increase this time. You can do it if you host your function on a App Service plan.

Quartz.net - misfire instructions don't work

I am using quartz.net with CRON scheduling.
I set misfire instruction to : fire and proceed:
trigger = Quartz.TriggerBuilder.Create()
.WithIdentity(jobData.JobId, jobData.ClientApplicationId.ToString())//.WithCronSchedule(scheduleInfo.CronExpression, WithMisfireHandlingInstructionDoNothing())
.WithSchedule(Quartz.CronScheduleBuilder.CronSchedule(new Quartz.CronExpression(scheduleInfo.CronExpression)).WithMisfireHandlingInstructionFireAndProceed())//.WithMisfireHandlingInstructionDoNothing()) ///.WithMisfireHandlingInstructionFireAndProceed()
.StartAt(DateTime.Now).ForJob(iJobDetail)
.Build();
From what I read, if a trigger was missed , it should fire as soon as the scheduler is up
(one time maximum, even if the job was suppose to run many times).
For some reason when I test it, the job is never triggered.
Say I have a job that should run every hour starting from 4:00.
I turn on the scheduler at 7:30 , I don't get any trigger fires - until 8:00.
misfireThreshold is set to (60000) - one minute.
The job is statefuul and does not allow concurrent runs.
I am using a persistent store (AdoJobStore) -saving the schedules to the MSSQL DB.
Any idea why the trigger isn't firing on schedule activation?
Try the code below instead. Make sure to replace {YourCronExpressionString} with your own cron expression.
trigger = Quartz.TriggerBuilder.Create()
.WithIdentity(jobData.JobId, jobData.ClientApplicationId.ToString())
.WithCronSchedule("{YourCronExpressionString}", x => x.WithMisfireHandlingInstructionFireAndProceed())
.StartAt(DateTime.Now).ForJob(iJobDetail)
.Build();
Source: Quartz.NET setting MisfireInstruction
try to use PauseJob(jobKey) method to missfire
use ResumeJob(jobKey) method to trigger it again
for example:
set cronexpression:every 4 hours
at 7:30 , call pauseJob method
and at 8:01,call resumeJob method
the job at 8:00 will be refire

Categories