I want to create some functions in ASP.NET Web API, which should be executed daily at specific time and do specific task like update statuses/Records/Generating Emails, SMS.
Should i create a TaskService in Code
using System;
using Microsoft.Win32.TaskScheduler;
class Program
{
static void Main(string[] args)
{
// Get the service on the local machine
using (TaskService ts = new TaskService())
{
// Create a new task definition and assign properties
TaskDefinition td = ts.NewTask();
td.RegistrationInfo.Description = "Does something";
// Create a trigger that will fire the task at this time every other day
td.Triggers.Add(new DailyTrigger { DaysInterval = 2 });
// Create an action that will launch Notepad whenever the trigger fires
td.Actions.Add(new ExecAction("notepad.exe", "c:\\test.log", null));
// Register the task in the root folder
ts.RootFolder.RegisterTaskDefinition(#"Test", td);
// Remove the task we just created
ts.RootFolder.DeleteTask("Test");
}
}
}
or should i create a .bat file and create a new task in Task Scheduler.
As you have mentioned in the question, you need to do the specific tasks like update statuses/Records/Generating Emails, SMS etc.
So database access comes into the scenario and on the other hand, you will have to send emails and SMS's which may require third party libraries or other configuration setting access.
Thus, to do all this it will be better to go with code implementation via which you can maintain your changes and requirements well enough.
About the ".bat file and windows scheduler", you need to have great skills using the limited batch commands available to fulfill your requirement.
So, my suggestion is code, .exe and windows scheduler task.
Also, this should be a separate application, don't mix it up with Web API code. You can always create a new project in the web API solution with web API project and reuse whatever code is possible.
You should do this outside your web code. This is because your webapp should have no access to the task system or web service. By default IIS 7.5+ runs app's in their own limited user account (https://www.iis.net/learn/manage/configuring-security/application-pool-identities).
If you want to have a reliable tasks scheduling wherein you can apply time interval depend on your choice, I recommend [quartz]: https://www.quartz-scheduler.net/. Quartz allow to add/edit/delete/etc a scheduled task easily, manageable and no CPU overhead.
Moreover Quartz is an open source job scheduling system that can be used from smallest apps to large scale enterprise systems.
I recommend you to try Hangfire. It's free and you can use it for free in commercial app. Ducumentation you can find here.
Related
Azure Functions have a time limit of 10 minutes. Suppose I have a long-running task such as downloading a file that takes 1 hr to download.
[FunctionName("PerformDownload")]
[return: Queue("download-path-queue")]
public static async Task<string> RunAsync([QueueTrigger("download-url-queue")] string url, TraceWriter log)
{
string downloadPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString);
log.Info($"Downloading file at url {url} to {downloadPath} ...");
using (var client = new WebClient())
{
await client.DownloadFileAsync(new Uri(url), myLocalFilePath);
}
log.Info("Finished!");
}
Is there any hacky way to make something like this start and then resume in another function before the time limit expires? Or is there a better way altogether to integrate some long task like this into a workflow that uses Azure Functions?
(On a slightly related note, is plain Azure Web Jobs obsolete? I can't find it under Resources.)
Adding for others who might come across this post: Workflows composed of several Azure Functions can be created in code using the Durable Functions extension, which can be used to create orchestration functions that schedule async tasks, shut down, and are reawakened when said async work is complete.
They're not a direct solution for long-running tasks that require an open TCP port, such as downloading a file, (for that, a function running on an App Service Plan has no execution time limit), but it can be used to integrate such tasks into a larger workflow.
Is there any hacky way to make something like this start and then
resume in another function before the time limit expires?
If you are on a Consumption Plan you have no control over how long your Function App runs, and so it would not be reliable to use background threads that continue running after your Function entry point completes.
On an App Service plan you're running on VMs you pay for, so you can configure your Function App to run continuously. Also AFAIK you don't have to have a Function timeout on an App Service Plan, so your main Function entry point can run for as long as you want.
Or is there a better way altogether to integrate some long task like this into a workflow that uses Azure Functions?
Yes. Use Azure Data Factory to copy data into Blob Storage, and then process it. The Data Factory pipeline can call Functions both before and after the copy activity.
One additional option, depending on the details of your workload, is to take advantage of Azure Container Instances. You can have your Azure Function spin up a container, process your workload (download your file \ do some processing, etc), and then shut down your container for you. Spin up time is typically a few seconds and you only pay for what you use (no need for a dedicated app service plan or vm instance). More details on ACI here.
10 minutes (based on the timeout setting in the host.json file) after the last function of your function app has been triggered, the VM running your function app will stop.
To prevent this behavior to happen, you can have an empty Timertrigger function that runs every 5 minutes. it wont cost anything and will keep your app up and running.
I think the issue is related with the Cold Start state. Here you can find more details about it.
https://markheath.net/post/avoiding-azure-functions-cold-starts
What you can do is, create an trigger azure function that "ping" your long running function to keep it "warm"
namespace NewProject
{
public static class PingTimer
{
[FunctionName("PingTimer")]
public static async Task Run([TimerTrigger("0 */4 * * * *")]TimerInfo myTimer, TraceWriter log)
{
// This CRON job executes every 4 minutes
log.Info($"PingTimer function executed at: {DateTime.Now}");
var client = new HttpClient();
string url = #"<Azure function URL>";
var result = await client.GetAsync(new Uri(url));
log.Info($"PingTimer function executed completed at: {DateTime.Now}");
}
}}
I have a queue of fire and forget jobs and my queue is configured to execute every 10 minutes, like this:
var options = new SqlServerStorageOptions
{
QueuePollInterval = TimeSpan.FromMinutes(10)
};
Although the jobs are "fire and forget" i dont want to wait 10 minutes, i want to process the queue right now. How to do this?
I'm assuming you mean that you want to keep your code as is (with the 10 minute PollingInterval) but need a mechanism to force jobs to run immediately when required - in which case I think you should be able to use the Hangfire Dashboard UI, where you can see a detailed breakdown of all jobs, as well as retry/trigger now etc.
To install it, just add the Nuget package: Hangfire.Dashboard.Authorization
and then add the config appropriate to your app type from the following link - it normally just works.
http://docs.hangfire.io/en/latest/configuration/using-dashboard.html
Update - WinForms
For a WinForms project, I think your best option is still the Dashboard (which you can host in an OWIN server hosted on your localhost from within your application - its easier than you might think)
Here are a few references:
https://www.codeproject.com/tips/854141/how-to-self-host-web-api-in-asp-net-web-forms-appl
http://www.c-sharpcorner.com/UploadFile/4b0136/working-with-owin-hosting-and-self-hosting-in-Asp-Net/ (see last section)
I have a windows application in Dot-net which consists of various Analytics tests. When user select a particular test(Checkbox) and submit it (clicking the button) then at the back-end SQL query gets executed and user gets a result-set of that particular test.
Now a requirement is, user will select a particular test and will give a time-stamp (time at which test will run) to get the output at his email ID using auto scheduler (without any user intervention with application). Auto scheduler will get triggered at specified time and will run the specific selected tests.
How to implement Auto scheduler with Windows application? I am trying to create Windows service in Dot-net but issue is how this service get the instance of Windows application and how it will run the selected tests using scheduler approach?
As per my understanding, I can run only script file using scheduler hence how to achieve this auto-scheduling of these tests of Windows application in Dot-net.
You can use the Task Scheduler Managed Wrapper. Download it manually and reference from your project or install using nuget packages. The example source code and more information are to be found here: Creating Scheduled Tasks
using System;
using Microsoft.Win32.TaskScheduler;
class Program
{
static void Main(string[] args)
{
// Get the service on the local machine
using (TaskService ts = new TaskService())
{
// Create a new task definition and assign properties
TaskDefinition td = ts.NewTask();
td.RegistrationInfo.Description = "Does something";
// Create a trigger that will fire the task at this time every other day
td.Triggers.Add(new DailyTrigger { DaysInterval = 2 });
// Create an action that will launch Notepad whenever the trigger fires
td.Actions.Add(new ExecAction("notepad.exe", "c:\\test.log", null));
// Register the task in the root folder
ts.RootFolder.RegisterTaskDefinition(#"Test", td);
// Remove the task we just created
ts.RootFolder.DeleteTask("Test");
}
}
}
Cheers,
I want to trigger an Azure Webjob 24Hours after I have added a record to a database using .NET . Obviously there will be multiple tasks for the Webjob to handle, all at their designated time. Is there a way ( in the Azure Library for .NET) in which i can schedule this tasks ?
I am free to use Message Queues , but I want to try and avoid the unnecessary polling of the WebJob for new messages.
If you want to trigger the execution of a WebJob 24 hours after a record insertion in a SQL database I would definitely use Azure Queues for this. So after you insert the record, just add a message to the queue.
In order to do this you can easily leverage the initialVisibilityDelay property that can be passed to the CloudQueue.AddMessage() method. This will make the message invisible for 24 hours in your case, and then it will appear to be processed by your Webjob. You don't have to schedule anything, just have a Continuous WebJob listening to a queue running.
Here's some sample code:
public void AddMessage(T message, TimeSpan visibilityDelay)
{
var serializedMessage = JsonConvert.SerializeObject(message);
var queue = GetQueueReference(message);
queue.AddMessage(new CloudQueueMessage(serializedMessage), null, visibilityDelay);
}
private static CloudQueue GetQueueReference(T message)
{
var storageAccount = CloudStorageAccount.Parse("Insert connection string");
var queueClient = storageAccount.CreateCloudQueueClient();
var queueReference = queueClient.GetQueueReference("Insert Queue Name");
queueReference.CreateIfNotExists();
return queueReference;
}
Hope this helps
Since the event of adding a record to the database is the trigger here, You can use Azure Management Libraries to create a Azure Scheduler Job to execute after 24hrs from the time the db record is inserted. Azure Scheduler Jobs can do only 3 things : make HTTP/HTTPS requests or Put Message in Queue. Since you do not want to poll queues, here are two options
Deploy the existing Web Job as Wep API where each task is reachable by unique URLs, so that the scheduler task can execute the right HTTP/HTTPS request
Create a new WebAPI/Wep API which takes accepts request (like a man in the middle) and pro-grammatically run the existing web job on demand, again using Azure management libraries.
Please let me know if any of these strategies help.
To invoke a WebJob from your Website,is not good idea rather than you can add the WebJob code inside your Website and simply call that code. you can still easily use the WebJob SDK from inside your Website.
https://github.com/Azure/azure-webjobs-sdk-samples
we wouldn't recommend to invoke the WebJob from your Website is that the invocation contains a secret you rather not store on your Website (deployment credentials).
Recommendation:
To separate WebJob and Website code, the best thing to do is to communicate using a queue, the WebJob listens on the queue and the Website pushes the request to the queue.
I have an ASP .NET page which allows users to start programs. These programs and the parameter are stored in a database and a windows service then executes these programs.
The programs are dlls which implements my IPlugin interface, so I can add them at runtime (the dlls are loaded at runtime so I can add them at runtime without compiling or restarting the service).
I created the ASP .NET page, more than 10 programs (plugins) and the windows service. Everything is running fine, but I think the implementation of the windows service is bad.
The windows service periodically queries the database and executes the needed program if it gets a new entry. The service can run multiple programs in parallel (at the moment 3 programs).
Currently my service method looks like this:
while (Alive)
{
// gets all running processes from the database
Processes = Proc.GetRunningProcs();
// if there are less than 3 processes running and
// a process is in queue
if (ReadyToRun())
{
// get next program from queue, sets the status to
// runnig and update the entry in the database
Proc.ProcData proc = GetNextProc();
proc.Status = Proc.ProcStatus.Running;
Proc.Update(proc);
// create a new thread and execute the program
Thread t = new Thread(new ParameterizedThreadStart(ExecuteProc));
t.IsBackground = true;
t.Start(proc);
}
Thread.Sleep(1000);
}
I have a method that queries the database for entries with status 'Canceling' (if a user cancels a program, the status will be set to 'Canceling') and does a Thread.Abort().
Is there a better practice? Like using tasks with the cancel mechanism or is the whole concept (storing the processes in database (program name, parameter, status,... and querying this information periodically) wrong?
As an alternative you can use some existing libraries for your purposes like Quartz.NET http://www.quartz-scheduler.net/. It takes care about job persistence, job scheduling and many other things. All you must do to create an adapter and put it into Windows Service.