Debug Azure WebJob locally - c#

I've been creating an Azure WebJob, it works aparently fine but I need to create a new function and I need test locally before upload to production site, I run on Debug the console program and this recognize all functions but I can't trigger any function.
Documentation say next trigger is every minute.... (https://github.com/Azure/azure-webjobs-sdk-extensions#timertrigger)
My code:
public static async void ProcessAugustEndowments([TimerTrigger("0 */1 * * * *", RunOnStartup = true)] TimerInfo timerInfo)
{
Console.WriteLine("Endowments process tried");
await endowmentNotification();
}
Output:

I run on Debug the console program and this recognize all functions but I can't trigger any function.
Based on your code, I tested it on my side and found that when my firstly debug the application, then I could get the following output:
But, when I restarted the application, I found that it would take some time for the function to be triggered.
Please make sure that you have installed the latest version packages of "Microsoft.Azure.WebJobs" and "Microsoft.Azure.WebJobs.Extensions". For more details, you could follow this tutorial.
And please try to reduce the time interval in your TimerTrigger and wait for a period when the job host has started, then try to find out whether the function could be triggered on your side. Here is my code sample, you could refer to it.
Program.cs
static void Main()
{
JobHostConfiguration config = new JobHostConfiguration();
// Add Triggers and Binders for Timer Trigger.
config.UseTimers();
JobHost host = new JobHost(config);
//host.RunAndBlock();
host.Start();
Console.WriteLine("[{0}] Job Host started!!!", DateTime.Now);
Console.ReadLine();
}
Function.cs
//Function triggered by a timespan schedule every 5 sec.
public static async void ProcessAugustEndowments([TimerTrigger("*/5 * * * * *", RunOnStartup = true)] TimerInfo timerInfo)
{
Console.WriteLine("Endowments process tried");
await endowmentNotification();
}
private static async Task endowmentNotification()
{
//sleep for 2 sec to simulate processing business logic
await Task.Delay(TimeSpan.FromSeconds(2));
}
Additionally, if the TimerTrigger could not meet your requirement, you could refer to this official tutorial to create a schedule WebJob, also you could refer to this blog.

If your functions are not triggered, I presume it is because you didn't configure your JobHost you use TimerTrigger:
var config = new JobHostConfiguration();
config.UseTimers();
How the JobHost works with Triggers :
When the JobHost starts, it discovers and indexes the functions with some *TriggerAttribute.
By Specifying the config.UseTimers(); you tell to the JobHost to index functions with TimerTriggerAttribute.
This is also valid for others types of triggers like ServiceBusTrigger that need config.UseServiceBus() to work

Related

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

Azure timertriggered webjob hangs randomly

I want to schedule a timertriggered method to call other methods but somehow the CronJob method won't run if I use it to call one of my own methods, I simply get this console output:
"
Found the following functions:
...ProcessQueueMessage
...Functions.CronJob
Job host started
"
and nothing else happens for a couple of minutes and then it might suddenly start working. But if I only use the CronJob() method for running it's own Console.WriteLine("Timer job fired") statement everything works.
I have been trying to find a solution to this problem for hours now but no one seems to have the same problem. Any ideas on what I'm doing wrong?
public static void CronJob([TimerTrigger("*/3 * * * * *", RunOnStartup = true)] TimerInfo timerInfo)
{
Console.WriteLine("Timer job fired! ");
DoTask();
}
private static void DoTask()
{
Console.WriteLine("Doing task...");
}
Main method:
static void Main()
{
var config = new JobHostConfiguration();
if (config.IsDevelopment)
{
config.UseDevelopmentSettings();
}
var host = new JobHost(config);
config.UseTimers();
// The following code ensures that the WebJob will be running continuously
host.RunAndBlock();
}
Any ideas on what I'm doing wrong?
According to your description, it is not related with whether you call code directly. The root reason is that a blob lease (the Singleton Lock) is taken for a default time of 30 seconds.
As Rob Reagan mention that you could set JobHostConfiguration.Tracing.ConsoleLeve
to Verbose. When the webjob hangs you could get the information "Unable to aquire Singleton lock".
For more detail info you could refer to this issue.
When the listener starts for a particular TimerTrigger function, a blob lease (the Singleton Lock) is taken for a default time of 30 seconds. This is the lock that ensures that only a single instance of your scheduled function is running at any time. If you kill your console app, that lease will still be held until it expires naturally

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.

how to make scheduled process in asp.net/C# with mvc5

I have a MVC5 application that has a function to send e-mail to user after subscribing the newsletter. Now i have a requirement to send e-mail to all those users whose are running 1 month ahead of expiry date of their subscription. In this case i need to implement a background process that will run every day at a specific time on the web server. How can i do that?
Thanks
You can create a Windows Service to make that work for you.
You should follow this tutorial.
You can store the date/time on the project web.config/app.config which when you want your service to be executed. When the service executes, you validate the time and call a generic function that will do what you want. Follow this example:
public partial class Service1 : ServiceBase
{
YourServiceClass service;
private Timer serviceTimer;
public Service1()
{
InitializeComponent();
service = new YourServiceClass();
}
protected override void OnStart(string[] args)
{
TimerCallback timerDelegate = new TimerCallback(service.GetData); // You should add this function to your class. You have an example below
string time = System.Configuration.ConfigurationSettings.AppSettings["SceduleTime"]; // Gets time from app.config like 12:50
string[] timeS = time.Split(':');
DateTime DateIni = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, Convert.ToInt32(timeS[0]), Convert.ToInt32(timeS[1]), 0);
TimeSpan diff = DateTime.Now - DateIni;
if (diff.TotalSeconds < 0)
diff = DateIni - DateTime.Now;
else
diff = DateIni.AddDays(1) - DateTime.Now;
// create timer and attach our method delegate to it
serviceTimer = new Timer(timerDelegate, service, diff, new TimeSpan(1, 0, 0, 0));
}
protected override void OnStop()
{
serviceTimer.Dispose();
}
}
And on your YourServiceClass class, you add this function:
public void GetData(object state){
// Do something...
}
Hope it helps!
Personally, I'd create a separate dedicated Windows Service to periodically check for expiry, and then call the code to send the emails.
An alternative is to create a simple console application to run the task, and call it using the Windows Task Scheduler.
A less secure method is to use a ping service, to periodically hit a page with an obfuscated URL which processes the emails.
A slightly old, but relevant blog post, detailing the issues with recurrent background tasks in .net sites can be read here.
I recommend you to use Quartz library. Your process should be independent from your web application since the web app will recycle from time to time based on the user traffic which will trigger Application_End event and will start once a new request is sent which will trigger Application_Start so you wont be able to manage correctly your schedule start and end.
It really depends on your requirements, and whether you want this update to be truly independent on the server, in a web application or bundled with your app.
I recently found a great third party library for ASP.NET called Hang Fire.
It looks like it can be as simple as:
RecurringJob.AddOrUpdate(
() => Console.WriteLine("Transparent!"),
Cron.Daily);
It supports:
Delayed Jobs
Recurring Tasks
Automatic Retries
And it has a nicely themed Management/Reporting interface
I'm planning to use it for some scheduled batch tasks I need to run on a CRM system. No experience with it yet, but it does seem to have some great features and I think I've seen it recommended a few times around Stack Overflow!
There are a ton of different ways to approach what you want (Scheduled Task on the server is another off the top of my head). This is a nice little package that lets me bundle it with my web applications.

C# Topshelf TimeoutException

As a First step I created Windows Service project configured it properly and
On second Step I have added TopShelf Version 3.1.135.0 in my project If I run my service through (F5 Run) then it is loading Top-shelf Console and service is completed successfully.
However When I am running it to install and Start it from command prompt I am having below TimeOut Error.
Topshelf.Hosts.StartHost Error: 0 : The service failed to start., System.Service
Process.TimeoutException: Time out has expired and the operation has not been co
mpleted.
public class AppService
{
LoggingService loggingService = new LoggingService(typeof(AppService).Name);
public void Start()
{
loggingService.Info("SampleService is Started");
ExtractProcess.Start();
TransformProcess.Start();
}
public void Stop()
{
loggingService.Info("SampleService is Stopped");
}
}
-- Updated Code to fix this issue
public void Start()
{
loggingService.Info("MPS.GOA.ETLService is Started");
ThreadStart myThreadDelegate = new ThreadStart(StartService);
Thread myThread = new Thread(myThreadDelegate);
myThread.Start();
}
private void StartService()
{
timer.Elapsed += new System.Timers.ElapsedEventHandler(OnElapsedTime);
timer.Interval = 60000 * ServiceIntervalInMinutes; //1 minute 60000 milliseconds
timer.Enabled = true;
Process();
}
private void Process()
{
ExtractProcess.Start();
TransformProcess.Start();
}
Any Suggestions?
This error is happening because you are running the extract and process methods in the Start method of the service. This is OK in Visual Studio, but when you install the service and start it, the Service Control Manager waits for the Start method to return, and if it does not do so within a certain time (30 seconds by default) then it will return this error.
You have several options, all of which will allow the Start method to return immediately:
Invoke the extract and transform methods on a separate thread
Invoke the extract and transform methods asynchronously
Use a timer to start the extract and transform process
In case you (like me) is struggling to get the service to start - and all you've found so far is references to starting work in a separate thread (and you already did) this might be the solution right here..
My problem was that I had an external JSON config file being read from the project's directory path. What I needed was to get the assembly path, so that when the .NET application is published and installed with Topshelf - it looks for the config file at the right place.
string assemblyPath = Path.GetDirectoryName(typeof(MyConfigManagerClass).Assembly.Location);
var builder = new ConfigurationBuilder()
.SetBasePath(assemblyPath)
.AddJsonFile("config.json", optional: false);
myConfigurationObject = builder.Build();
Topshelf gave an error saying the service couldn't be started, but now I finally know why.
In my case it was neither of the above solutions that solved it, but actual permissions within the topshelf service, that required access to a file that resided in an external server.
TopShelf program running on test server
Log file located on Production server
Test server does not have access to external servers, for security
reasons.
So I changed the program to refer everything internally inside it's own server, and it worked fine.

Categories