Running a background process/task updating database - asp.net

I'm trying to find the way to keep the database updated, but the method which does it consumes a lot of time so I try to create a background task to do it.
I searched for solutions and I read this article of different options to run background processes: https://www.hanselman.com/blog/HowToRunBackgroundTasksInASPNET.aspx
But I don't know what's is the best solution out of those, like I'm trying to execute it outside the application. I found something about creating a Windows Service too, but I don't know how, I didn't manage to find some good examples.
What is the best way to keep my database updated everytime I access the application without losing the time it consumes? If you can help me to see the light I would appreciate that so much.

I'm really happy with FluentScheduler, which is handling all my mission-critical scheduling. As well as firing jobs on a scheduled basis, it can also do them on demand, like so:
// Define your job in its own class
public abstract class MyJob : IJob
{
public void Execute()
{
// Do stuff here...
}
}
// Schedule your job at startup
var runAt = DateTime.Today.AddHours(1); // 1am
if (runAt<DateTime.Now)
runAt = runAt.AddDays(1);
Schedule<MyJob>()
.WithName("My Job Name") // Job name, required for manually triggering
.NonReentrant() // Only allow one instance to run at a time
.ToRunOnceAt(runAt) // First execution date/time
.AndEvery(1).Days().At(runAt.Hour, runAt.Minute); // Run every day at the same time
// To manually trigger your job
ScheduledJobRegistry.RunTaskAsync("My Job Name");
I have the scheduled jobs running in a windows Service and use SignalR as a means of triggering them remotely from an MVC Web App when required.

You can use an async method. Just use a void instead of Task.
public async void LongRunningMethod () {
...
// Insert long running code here
...
}
Then call it and it will execute in the background. Be aware that you can have hidden exceptions without proper were handling.
You can also use Hangfire which is a pretty awesome background task scheduler
Here is an example of using Hangfire to run a daily task
RecurringJob.AddOrUpdate(() => Console.Write("Easy!"), Cron.Daily);

Related

How to make command to wait until all events triggered against it are completed successfully

I have came across a requirement where i want axon to wait untill all events in the eventbus fired against a particular Command finishes their execution. I will the brief the scenario:
I have a RestController which fires below command to create an application entity:
#RestController
class myController{
#PostMapping("/create")
#ResponseBody
public String create(
org.axonframework.commandhandling.gateway.CommandGateway.sendAndWait(new CreateApplicationCommand());
System.out.println(“in myController:: after sending CreateApplicationCommand”);
}
}
This command is being handled in the Aggregate, The Aggregate class is annotated with org.axonframework.spring.stereotype.Aggregate:
#Aggregate
class MyAggregate{
#CommandHandler //org.axonframework.commandhandling.CommandHandler
private MyAggregate(CreateApplicationCommand command) {
org.axonframework.modelling.command.AggregateLifecycle.apply(new AppCreatedEvent());
System.out.println(“in MyAggregate:: after firing AppCreatedEvent”);
}
#EventSourcingHandler //org.axonframework.eventsourcing.EventSourcingHandler
private void on(AppCreatedEvent appCreatedEvent) {
// Updates the state of the aggregate
this.id = appCreatedEvent.getId();
this.name = appCreatedEvent.getName();
System.out.println(“in MyAggregate:: after updating state”);
}
}
The AppCreatedEvent is handled at 2 places:
In the Aggregate itself, as we can see above.
In the projection class as below:
#EventHandler //org.axonframework.eventhandling.EventHandler
void on(AppCreatedEvent appCreatedEvent){
// persists into database
System.out.println(“in Projection:: after saving into database”);
}
The problem here is after catching the event at first place(i.e., inside aggregate) the call gets returned to myController.
i.e. The output here is:
in MyAggregate:: after firing AppCreatedEvent
in MyAggregate:: after updating state
in myController:: after sending CreateApplicationCommand
in Projection:: after saving into database
The output which i want is:
in MyAggregate:: after firing AppCreatedEvent
in MyAggregate:: after updating state
in Projection:: after saving into database
in myController:: after sending CreateApplicationCommand
In simple words, i want axon to wait untill all events triggered against a particular command are executed completely and then return to the class which triggered the command.
After searching on the forum i got to know that all sendAndWait does is wait until the handling of the command and publication of the events is finalized, and then i tired with Reactor Extension as well using below but got same results: org.axonframework.extensions.reactor.commandhandling.gateway.ReactorCommandGateway.send(new CreateApplicationCommand()).block();
Can someone please help me out.
Thanks in advance.
What would be best in your situation, #rohit, is to embrace the fact you are using an eventually consistent solution here. Thus, Command Handling is entirely separate from Event Handling, making the Query Models you create eventually consistent with the Command Model (your aggregates). Therefore, you wouldn't necessarily wait for the events exactly but react when the Query Model is present.
Embracing this comes down to building your application such that "yeah, I know my response might not be up to date now, but it might be somewhere in the near future." It is thus recommended to subscribe to the result you are interested in after or before the fact you have dispatched a command.
For example, you could see this as using WebSockets with the STOMP protocol, or you could tap into Project Reactor and use the Flux result type to receive the results as they go.
From your description, I assume you or your business have decided that the UI component should react in the (old-fashioned) synchronous way. There's nothing wrong with that, but it will bite your *ss when it comes to using something inherently eventually consistent like CQRS. You can, however, spoof the fact you are synchronous in your front-end, if you will.
To achieve this, I would recommend using Axon's Subscription Query to subscribe to the query model you know will be updated by the command you will send.
In pseudo-code, that would look a little bit like this:
public Result mySynchronousCall(String identifier) {
// Subscribe to the updates to come
SubscriptionQueryResult<Result> result = QueryGateway.subscriptionQuery(...);
// Issue command to update
CommandGateway.send(...);
// Wait on the Flux for the first result, and then close it
return result.updates()
.next()
.map(...)
.timeout(...)
.doFinally(it -> result.close());
}
You could see this being done in this sample WebFluxRest class, by the way.
Note that you are essentially closing the door to the front-end to tap into the asynchronous goodness by doing this. It'll work and allow you to wait for the result to be there as soon as it is there, but you'll lose some flexibility.

Background URLSession on watchOS - what is the cycle?

I have a class with the delegates for a URLSession. I intend to use it with a background configuration. I understand that the handlers are called when a certain event happens, such as didFinishDownloadingTo.
However, I do have the handle function on my ExtensionDelegate class:
func handle( _ handleBackgroundTasks:
Set<WKRefreshBackgroundTask>)
// Sent when the system needs to launch the application in the background
to process tasks. Tasks arrive in a set, so loop through and process each one.
for task in handleBackgroundTasks {
switch task {
case let urlSessionTask as WKURLSessionRefreshBackgroundTask:
I wonder: where should I handle the data I receive after a download? At the didFinishDownloadingTo or at that function on my ExtensionDelegate class, on the appropriate case of the switch statement?
Another question on the same cycle: I read everywhere that one must remember to setTaskCompleted() after going through the background tasks. But I read elsewhere that one should not set a task as completed if the scheduled data transfer hasn't finished. How do I check that?
There is a very good explanation here.enter link description here
It worked when I had an array with my WKURLSessionRefreshBackgroundTask. Then, at the end of my didFinishDownloadingTo, I get the task on that array that has the same sessionIdentifier as the current session.configuration.identifier, and set it as complete.

Async web calls bottlenecking and running sequencially

I have a web site which makes frequent requests to an external web service, and I'd like these calls to be async and parallel to avoid blocking and to speed up the site a bit. Basically, I have 8 widgets, each of which has to make its own web call(s).
For some reason, only the first 3 or so of them truly load async, and then the threads don't free up in time, and the rest of the widgets load sequencially. If i could get 3 of them to load in parallel, then 3 more in parallel, then 2 more in parallel, i'd be happy. So the issue is really that the threads aren't freeing up in time.
I'm guessing the answer has to do with some IIS configuration. I'm testing on a non-server OS, so maybe that's part of it.
Edit for #jon skeet:
I'm using reflection to invoke the web calls like this:
output = methodInfo.Invoke(webservice, parameters);
The widget actions (which eventually call the web service) are called via a jquery $.each() loop and the .load function (maybe this causes a bottleneck?). The widget actions are set up as async methods in an async controller.
Here is the code for one of the async methods (they are all set up like this):
public void MarketTradeWidgetAsync()
{
AsyncManager.OutstandingOperations.Increment();
//a bunch of market trade logic
//this eventually calls the web service
PlanUISetting uiSettingMarketQuotesConfig = WebSettingsProviderManager.Provider.GetMarketQuotes(System.Configuration.ConfigurationManager.AppSettings["Theme"], SessionValues<String>.GlobalPlanID, SessionValues<String>.ParticipantID, "MARKETQUOTES");
AsyncManager.OutstandingOperations.Decrement();
}
public ActionResult MarketTradeWidgetCompleted(MarketTradeTool markettradetool)
{
if (Session.IsNewSession)
return PartialView("../Error/AjaxSessionExpired");
else
{
ViewData["MarketData"] = markettradetool;
return PartialView(markettradetool);
}
}
And, like I said, these methods are called via jquery. My thinking is that since the action methods are async, they should give control back to the jquery after they get called, right?
SessionState = "readonly" for the page at hand fixed this issue. Evidently session locking was the issue.

Timer Class in ASP.NET

I have this code in the asp.net application start evert, and I'm not really familar with the Timer class but what I want to do is have one Trigger that goes off every night at 11 pm, one that goes off at 5:30 in the morning and then every hour after that.
private System.Threading.Timer timer;
protected void Application_Start(object sender, EventArgs e)
{
int intervalMilliseconds = 60 * 1000;
timer = new System.Threading.Timer(new System.Threading.TimerCallback(TimedEvent), null, intervalMilliseconds, intervalMilliseconds);
}
protected void Application_End(object sender, EventArgs e)
{
if (timer != null) timer.Dispose();
}
private void TimedEvent(object stateInfo)
{
MyClass.ExecuteCode();
}
*Please no answers in the way of "don't use asp.net to do triggers because of the lifecycle".
*Again - please no posts on what not to use. I've received two post both telling me what not to use and both not related to my question which is about the Timer class and how to use it.
From your question i'm assuming you don't have full control over your hosting environment, so will try to avoid the schedule it... etc answers.
Having said that, you still need to be aware of the asp.net lifecycle, and your trigger approach is fraught with dangers.
Do you get enough traffic that the application won't end unexpectedly? Do you know the configuration of IIS, so recycling is not a worry?
I can see three approaches:
I would recommend having a page, which uses some sort of key, which is only known
by the caller. Have this page triggered by a watchmouse (See: http://www.watchmouse.com/en/), or scheduled crawler on a pc/server which will always be on, at the times you need it to be triggered.
An alternative would be to trigger a database process, which runs when needed to.
Depending on your environment, this can be scheduled too.
Another would be to check a log file, on users accessing the page, and if it is the first access within the hour, trigger your process. (Do this for whatever period you need.)
However this depends entirely on how heavily your site is accessed, and may not work reliably.
When you create your timer and hook up its tick/elapsed event, set the interval to be every 5 minutes or so.
Then in the tick/elapsed event handler, check the current time and perform an action where necessary. Obviously you will also need to record when an actino has been performed so you don't perform it at 10:58 and 11:03 pm.
Have a look at Quartz.NET, which will allow you to set up cron-like triggers.
Maybe a different way of doing what you want: Instead of relying on ASP to be active, perhaps you can just use the windows scheduler to schedule your event. It has more of the scheduling features you want and will be likely be more reliable as well as already debugged. Your timed event can be as simple as accessing http://localhost/YourApp/.aspx. You'll get the same effect with the added benefit that if your app happens to have recycled, your event will still execute as the 1st request.
You can do the kind of thing you're describing by using the inbuilt ASP.NET Cache.Add CacheItemRemovedCallback delegate. It's a bit of a roundabout way of using it, but you can do effective scheduling this way.
There's an article here showing how to do it.
More information on the CacheItemRemovedCallback here.
Edit: I know you said no services, but if you check the server and find you can use Scheduled Tasks, you can use that to run a console app on a specific schedule like some other other answers mention.

Quartz.NET trigger not firing

i am using Quartz.NET in my ASP.NET web application. i put the following code in a button click handler to make sure that it executes (for testing purposes):
Quartz.ISchedulerFactory factory = new Quartz.Impl.StdSchedulerFactory();
Quartz.IScheduler scheduler = factory.GetScheduler();
Quartz.JobDetail job = new Quartz.JobDetail("job", null, typeof(BackupJob));
Quartz.Trigger trigger = Quartz.TriggerUtils.MakeDailyTrigger(8, 30); // i edit this each time before compilation (for testing purposes)
trigger.StartTimeUtc = Quartz.TriggerUtils.GetEvenSecondDate(DateTime.UtcNow);
trigger.Name = "trigger";
scheduler.ScheduleJob(job, trigger);
scheduler.Start();
here's "BackupJob":
public class BackupJob : IJob
{
public BackupJob()
{
}
public void Execute(JobExecutionContext context)
{
NSG.BackupJobStart();
}
}
my question: why is "BackupJobStart()" not firing? i've used similar code before and it worked fine.
EDIT: #Andy White, i would have it in Application_Start in Global.asax. this doesn't work which is why i moved it to a button click handler to narrow down the problem.
Do you have the Quartz.NET logging hooked up? I once had a problem with a job not executing (I forget why), but once I got the Quartz.NET logging going, the problem was obvious.
It's worth a try (if you're not already doing it):
https://www.quartz-scheduler.net/documentation/quartz-2.x/quick-start.html
http://netcommon.sourceforge.net/
http://netcommon.sourceforge.net/documentation.html
Update: Simply add this to your program.cs to enable console logging:
Common.Logging.LogManager.Adapter = new Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter { Level = Common.Logging.LogLevel.Info};
Maybe it's a problem of time.
I've had the same problem as you, and I live in a country which time is UTC + 2. So, when I set the StartTimeUtc to the trigger, I used DateTime.Now, so the trigger didn't have to fire until two hours later, and I thought it has to be fired in the very moment my code started.
Look carefully the time of the trigger's execution and its StartTime
Another possibility is the way you're running the scheduler. I'm not totally sure, but you may run into problems trying to run a scheduling threads in an ASP.NET application. Putting the SchedulerFactory/Scheduler objects in a button click handler doesn't seem like it would give you the desired results.
You may need to create the scheduler at a more "global" level, so that it can run in the "background" of the application. It might also make sense to move any scheduled work into a separate windows service, so that you don't have to maintain the scheduler in the web app.
When you had success in the past, how were you invoking the scheduler?
In my case, there was an issue with IoC - there were some Interfaces that weren't implemented. I could see what was wrong with mine by adding logging:
Common.Logging.LogManager.Adapter = new Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter { Level = Common.Logging.LogLevel.Info};
to Program.cs as suggested by Andy White

Resources