Azure TimerTrigger is not working in .NET 7 Isolated Worker Process - c#

I'm trying to trigger an orchestrated function TimerTrigger in .NET 7. Below is the function I created
[Function(nameof(FunctionSampleTimer))]
public async Task Run([TimerTrigger("*/5 * * * * *", RunOnStartup = false)] MyInfo myTimer, [DurableClient] DurableTaskClient client, FunctionContext context)
{
var instanceid = Guid.NewGuid().ToString();
var logger = context.GetLogger("TimerFunction");
logger.LogInformation($"Function Ran. Next timer schedule = {myTimer.ScheduleStatus.Next}");
}
The above function is getting triggered once every 5 seconds only for the first time when the project is created, and is not getting triggered again and getting stuck on that "Host lock lease acquired..." line.
Console output shows this:
[2023-02-20T01:26:52.843Z] Azure Functions .NET Worker (PID: 49120) initialized in debug mode. Waiting for debugger to attach...
[2023-02-20T01:26:53.305Z] The next 5 occurrences of the 'FunctionSampleTimer' schedule (Cron: '0,5,10,15,20,25,30,35,40,45,50,55 * * * * *') will be:
[2023-02-20T01:26:53.307Z] 02/19/2023 17:26:55-08:00 (02/20/2023 01:26:55Z)
[2023-02-20T01:26:53.308Z] 02/19/2023 17:27:00-08:00 (02/20/2023 01:27:00Z)
[2023-02-20T01:26:53.309Z] 02/19/2023 17:27:05-08:00 (02/20/2023 01:27:05Z)
[2023-02-20T01:26:53.310Z] 02/19/2023 17:27:10-08:00 (02/20/2023 01:27:10Z)
[2023-02-20T01:26:53.311Z] 02/19/2023 17:27:15-08:00 (02/20/2023 01:27:15Z)
[2023-02-20T01:26:53.312Z]
[2023-02-20T01:26:53.323Z] Host started (775ms)
[2023-02-20T01:26:53.324Z] Job host started
[2023-02-20T01:26:54.472Z] {
[2023-02-20T01:26:54.473Z] "ProcessId": 49120,
[2023-02-20T01:26:54.474Z] "RuntimeIdentifier": "win10-x64",
[2023-02-20T01:26:54.475Z] "WorkerVersion": "1.8.0.0",
[2023-02-20T01:26:54.476Z] "ProductVersion": "1.8.0-local202209270007\u002B04ccbd8e45bb9017dc30ff5e1343e893a216e173",
[2023-02-20T01:26:54.477Z] "FrameworkDescription": ".NET 7.0.0",
[2023-02-20T01:26:54.478Z] "OSDescription": "Microsoft Windows 10.0.22621",
[2023-02-20T01:26:54.479Z] "OSArchitecture": "X64",
[2023-02-20T01:26:54.480Z] "CommandLine": "C:\\Users\\swkandhi\\source\\repos\\FunctionTimerTrigger\\FunctionTimerTrigger\\bin\\Debug\\net7.0\\FunctionTimerTrigger.dll --host 127.0.0.1 --port 58647 --workerId e70ddb42-819a-45b2-a17c-dca35392699d --requestId 326e359b-9d29-4105-b2f1-9ef01892ae95 --grpcMaxMessageLength 2147483647"
[2023-02-20T01:26:54.481Z] }
[2023-02-20T01:26:54.493Z] Worker process started and initialized.
[2023-02-20T01:26:55.053Z] Executing 'Functions.FunctionSampleTimer' (Reason='Timer fired at 2023-02-19T17:26:55.0194750-08:00', Id=872452e5-4d71-42ea-a16d-d4790ccf38a2)
[2023-02-20T01:26:57.821Z] Host lock lease acquired by instance ID '00000000000000000000000074E57A56'.

With what you have there for timing (5 * * * * *) I think it means it should run once at the 5 second mark. If you want it to run every 5 seconds you should do this (*/5 * * * * *)

I have observed for every minute and couple of minutes in .NET 7 Isolated Azure Functions with generating the GUID Id, it is working successfully:
Below are my test cases:
For every
1st Run
Next Runs
2 minutes
Yes
Yes
1 minute
Yes
Yes
60 seconds
Yes
Yes
30 Seconds
Yes
No
5 Seconds
Yes
No
For every minute:
For every 2 minutes:
For every 60 Seconds:
For every 5 Seconds:
AFAIK, the shortest interval requires at least 60 seconds minimum in the CRON Expression - the same is mentioned in the articles of Hostinger - Cron Job Tutorial.

Related

Incorrect job interval when using HangFire

I have 2 simple jobers GetMenuJober and GetOrdersJober. All they do is printing message in console, RunJob method is similar in both classes:
public async Task RunJob()
{
Console.WriteLine($"{this.GetType().Name} has been started.");
}
I planned to start these workers in 5 seconds:
RecurringJob.AddOrUpdate<GetOrdersJober>(x => x.RunJob(), "0/5 * * * * *");
RecurringJob.AddOrUpdate<GetMenuJober>(x => x.RunJob(), "0/5 * * * * *");
And expected to see something like this in the console:
GetOrdersJober has been started.
GetMenuJober has been started.
GetOrdersJober has been started.
GetMenuJober has been started.
GetOrdersJober has been started.
GetMenuJober has been started.
The intervals between the launches of both are different, while they are not equal to 5 seconds, sometimes 30, sometimes more than a minute. Jobs run completely different. What did I miss ?
Moreover, even if I set cron expression as Cron.Minutely both jobs will run in absolutely random interval.

How to run functionality only sometimes in an Azure function

I have an Azure function with a trigger to make it run once every 15 minutes:
TimerTrigger("0 */15 * * * *", RunOnStartup =false)
Within this function, there is some functionality that I only want to run once per hour. I am currently checking the minute of the current time to see whether it should run or not. But as I understand it, Azure function triggers are not always precise (this is running on a consumption-based app service), so instead I am checking for a range of minutes.
int currentMinute = DateTime.Now.Minute;
bool extraFunctionality = (currentMinute >= 58 && currentMinute <= 2);
This seems like it will work; only running this functionality during the ":00" runs, once per hour. However, it looks like bad code to me, for a couple reasons:
The up to 2 minutes early and 2 minutes late number was chosen pretty much arbitrarily; I don't have a good idea of what sort of time span to use there.
It relies on using DateTime.Now which will return different results depending on server settings, even though I don't care about anything other than the current minute.
The code simply doesn't read like the intent is to get it to run once per hour.
Is there a better / more proper way to do this within Azure functions? Can I either get information from the TimerInfo parameter or the ExecutionContext parameter about which 15-minute trigger caused the function to run? Or can I have a separate TimerTrigger which runs once per hour, and then have different functionality based on which of the 2 timers caused the function to trigger? Or is there some way to have the TimerTrigger itself pass in a parameter telling me which 15-minute window it is in?
Or, is my code fine as-is; perhaps with some adjustment to the number of minutes I allow it to be off?
You could create two Azure Functions, one which runs at 15, 30, 45 minutes past the hour and another which runs on the hour. Then in each of these functions set a variable for if it's runnin on the hour.
[FunctionName("HourlyFunction")]
public static void RunHourly([TimerTrigger("0 0 15,30,45 * * *")]TimerInfo myTimer, ILogger log)
{
_myService.Run(true);
}
[FunctionName("FifteenMinuteFunction")]
public static void RunEveryFifteen([TimerTrigger("0 0 * * * *")]TimerInfo myTimer, ILogger log)
{
_myService.Run(false);
}
Then have a separate service which can be called by those functions:
public class MyService : IMyService
{
public async Task Run(bool isHourlyRun)
{
// Do work here
}
}
* I'm not sure those cron expressions are correct

Hangfire Server not able to process recurring job for Process.Start(processstartinfo)

I have an ASP.NET Core Web App that I am trying to use Hangfire on to schedule background jobs (Calling exe's). Everything works with jobs queued like the tutorials:
backgroundJobs.Enqueue(() => Console.WriteLine("Hello world from Hangfire!"));
However, when I try to run:
RecurringJob.AddOrUpdate("job3", () => Process.Start(process), $"*/{interval} * * * *");
I can start the process from the program just fine without Hangfire. Do I need to make a separate process to host the Hangfire server and make sure that process has System.Diagnostics? Or do I need to Serialize the data myself and pass it to hangfire differently?
Instead of passing the processStartInfo, I went ahead and made a class and method where I only passed an int id which was easier to get serialized I guess.
RecurringJob.AddOrUpdate<JobRunner>($"Batch id {batchId}",x => x.RunBatchJob(batchId), $" */{interval} * * * *");

How to create recurring Hangfire job every 10 minutes for only 24 hours

When I have a new customer signup that does not complete the process, I send them an email with next steps. I need to create a job that runs every 10 minutes for the first 24 hours after signup. After that time, there is another process that takes over. I schedule the job like this:
RecurringJob.AddOrUpdate(customerId, () => new NewCustomerProcess().checkNewCustomerStatus(customerId)), "*/10 * * * *");
If I add a job start time to the job class:
private DateTime _jobstart = DateTime.UtcNow;
Can I inspect that within the job to figure out when 24 hours has passed then remove the job?
RecurringJob.RemoveIfExists(customerId);
Does Hangfire re-instantiate the job class every time it runs?
if i understand your question correctly.
Hangfire does create a new instance of the job class every time.
So if I needed to solve this problem, I would pass in DateTime as a parameter every time the job is created:
RecurringJob.AddOrUpdate(customerId, () => new
NewCustomerProcess().checkNewCustomerStatus(customerId, DateTime.Now.AddDays(2))), "*/10 * * * *");
And then in the checkNewCustomerStatus compare with DateTime.Now
if (DateTime.Now > dateEnqueued)
{
//Job is complete
return;
}

code running from alarm manager dying after 1 minute

I have some code that should take (roughly) 5 minutes to run. This code should run periodically, so I'm calling it using the built in AlarmManager.
Like this:
public void setAlarm(Context context)
{
AlarmManager am = (AlarmManager)context.GetSystemService(Context.AlarmService);
Intent i = new Intent(context, typeof(keyboardservice.alarmreciever));
PendingIntent pi = PendingIntent.GetBroadcast(context, 0, i, PendingIntentFlags.CancelCurrent);
am.SetRepeating(AlarmType.ElapsedRealtimeWakeup, 0, 1000 * 60 * 30, pi); // Millisec * Second * Minute
}
As you can see the code should run every 30 minutes.
AlarmService looks something like this :
[BroadcastReceiver(Enabled = true)]
public class alarmreciever : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Task.Delay(1000 * 300).Wait();
}
}
I've simplified the code above, but the result is the same the code dies after 1 minute (exactly), like there's some limit.
It doesn't matter if the screen is on or off.
What am I missing?
AlarmService looks something like this
That is not a Service. That is a BroadcastReceiver.
What am I missing?
First, your BroadcastReceiver is attempting to tie up the main application thread for five minutes. Even if that were possible, it would be a profoundly bad idea, as that means that your UI would be frozen during those five minutes. But, it is not possible, as a watchdog should terminate your work in the ANR timeout period (10-15 seconds for background work IIRC).
Second, in general, you cannot do anything in the background for more than a minute on Android 8.0+. There are exceptions, notably if you use JobScheduler, where you have ~10 minutes.
If you are sure that your work will be completed in less than 10 minutes, then if your minSdkVersion is 21 or higher, switch to JobScheduler. If your minSdkVersion is below 21, at least on those older devices, have your BroadcastReceiver start a JobIntentService, were you do your five minutes of work in onHandleWork().
Note that I do not know what of this has been Xamarin-ified, as I do not use Xamarin.
Solved with :
new Task(() =>
{
DoAction(context);
}).Start();

Categories

Resources