Long-running task without IHostedService running the entire life of the application? - c#

I have a website page that needs the option of performing an operation that could take several minutes. To avoid performance issues and time outs, I want to run this operation outside of the HTTP request.
After some research, I found IHostedService and BackgroundService, which can be registered as a singleton using AddHostedService<T>().
But my concern is that a hosted service is always running. Doesn't that seem like a waste of resources when I just want it to run on demand?
Does anyone know a better option to run a lengthy task, or a way to use IHostedService that doesn't need to run endlessly?
Note that the operation calls and waits for an API call. And so I cannot report the progress of the operation, nor can I set a flag in a common database regarding whether the operation has completed.

One option to run a lengthy task on demand while avoiding performance issues and time outs is to use a message queue. You can have your Razor Pages website send a message to the queue when the operation is requested, and have a separate service, such as a background worker, consume messages from the queue and perform the operation. This allows you to decouple the task from the web request, and also allows for the possibility of adding more worker instances to handle the workload.
Another option is to use a task scheduler that runs on demand, such as Hangfire. It allows you to schedule background jobs and monitor their progress, which can be useful in your scenario where you cannot report the progress of the operation.
You can also use IHostedService, but you need to make sure that the service is only running when it is needed. You can use a flag or a semaphore to control whether the service is running or not. You can set the flag or semaphore when the operation is requested, and clear it when the operation is completed. The service can then check the flag or semaphore in its main loop, and exit if the flag is not set.
In summary:
message queue, task scheduler, and IHostedService with controlling flag/semaphore are all viable options for running a lengthy task on demand. The best option depends on your specific use case and requirements.

Related

Proper way to start and fire-and-forget asynchronous calls?

I have an async call (DoAsyncWork()), that I would like to start in a fire-and-forget way, i.e. I'm not interesting in its result and would like the calling thread to continue even before the async method is finished.
What is the proper way to do this? I need this in both, .NET Framework 4.6 as well as .NET Core 2, in case there are differences.
public async Task<MyResult> DoWorkAsync(){...}
public void StarterA(){
Task.Run(() => DoWorkAsync());
}
public void StarterB(){
Task.Run(async () => await DoWorkAsync());
}
Is it one of those two or something different/better?
//edit: Ideally without any extra libraries.
What is the proper way to do this?
First, you need to decide whether you really want fire-and-forget. In my experience, about 90% of people who ask for this actually don't want fire-and-forget; they want a background processing service.
Specifically, fire-and-forget means:
You don't care when the action completes.
You don't care if there are any exceptions when executing the action.
You don't care if the action completes at all.
So the real-world use cases for fire-and-forget are astoundingly small. An action like updating a server-side cache would be OK. Sending emails, generating documents, or anything business related is not OK, because you would (1) want the action to be completed, and (2) get notified if the action had an error.
The vast majority of the time, people don't want fire-and-forget at all; they want a background processing service. The proper way to build one of those is to add a reliable queue (e.g., Azure Queue / Amazon SQS, or even a database), and have an independent background process (e.g., Azure Function / Amazon Lambda / .NET Core BackgroundService / Win32 service) processing that queue. This is essentially what Hangfire provides (using a database for a queue, and running the background process in-proc in the ASP.NET process).
Is it one of those two or something different/better?
In the general case, there's a number of small behavior differences when eliding async and await. It's not something you would want to do "by default".
However, in this specific case - where the async lambda is only calling a single method - eliding async and await is fine.
It depends on what you mean by proper :)
For instance: are you interested in the exceptions being thrown in your "fire and forget" calls? If not, than this is sort of fine. Though what you might need to think about is in what environment the task lives.
For instance, if this is a asp.net application and you do this inside the lifetime of a thread instantiated due to a call to a .aspx or .svc. The Task becomes a background thread of that (foreground)thread. The foreground thread might get cleaned up by the application pool before your "fire and forget" task is completed.
So also think about in which thread your tasks live.
I think this article gives you some useful information on that:
https://www.hanselman.com/blog/HowToRunBackgroundTasksInASPNET.aspx
Also note that if you do not return a value in your Tasks, a task will not return exception info. Source for that is the ref book for microsoft exam 70-483
There is probably a free version of that online somewhere ;P https://www.amazon.com/Exam-Ref-70-483-Programming-C/dp/0735676828
Maybe useful to know is that if your have an async method being called by a non-async and you wish to know its result. You can use .GetAwaiter().GetResult().
Also I think it is important to note the difference between async and multi-threading.
Async is only useful if there are operations that use other parts of a computer that is not the CPU. So things like networking or I/O operations. Using async then tells the system to go ahead and use CPU power somewhere else instead of "blocking" that thread in the CPU for just waiting for a response.
multi-threading is the allocation of operations on different threads in a CPU (for instance, creating a task which creates a background thread of the foreground thread... foreground threads being the threads that make up your application, they are primary, background threads exist linked to foreground threads. If you close the linked foreground thread, the background thread closes as well)
This allows the CPU to work on different tasks at the same time.
Combining these two makes sure the CPU does not get blocked up on just 4 threads if it is a 4 thread CPU. But can open more while it waits for async tasks that are waiting for I/O operations.
I hope this gives your the information needed to do, what ever it is you are doing :)

Reliable background queuing for task on IIS

I am trying to implement a queue to handle tasks queued by using task.run(function()).
Here are my requirements:
1) The threadpool should not stop after the application context has died. I need to be sure the calls will be made. (I believe this requires the thread to be a foreground thread)
2) Additionally, I need to be able to log these errors. Each function has it own error handling implemented within. I would consider it a fire and forget because I don't actually need to pass the data back to the caller but the information needs to be logged.
3) The queue will remove tasks as they complete. I may need some way of managing the size of the queue to prevent overuse of resources. Possibly, able to set a time limit for each task and forcing it to cancel after allotted time to free space queue.
Specification:
- .Net 4.0 Framework
- IIS
I was able to achieve the desire functionality by referencing Stephen Cleary AspNetBackgroundTasks
By using a singleton pattern, I was able to create a single instance of a object which is used as wrapper for managing the task. The code is able to prevent shut down by using the iregisteredobject.
Upon receiving a notification of pending shut down, Asp.Net notifies the object. Using a TaskCompleteSource, which only updates its state to a completed state when the running tasks count equal zero, the application await for all task to finish before allowing the application to shutdown.
There are risk in this design. The risk that is very similar to notification systems currently running in main memory. If power is lost, the code is lost.
Additionally, remember to make atomic changes to shared variables or implement thread safe locking techniques.

Service vs Thread

What should I use to make an application that will:
Ask the user for username and password
Authorize
Run an infinite loop in which it will fetch some data from the website every 10 seconds or so.
I want to be able to do some basic tasks in the meantime, or lock my screen without the thread getting killed. I don't want the service to continue running after I close the application, I just want to be sure the thread is never killed while it's running for a long time.
I also wanted to ask: Are services as easy to interact with as threads? Can I just pass a CancellationToken in it and cancel it when the user presses the stop button?
I also found the setThreadPriority, will it help in my case?
Services and Threads are totally different concepts. A Thread is a separate process that executes in parallel. A Service is a component of an app that doesn't have a UI and runs with a separate life cycle. A service does not run on its own thread, it runs on the UI thread (although it can launch a Thread if it wishes).
You use a Service if you want to do some task but not be bound to the Android Activity lifecycle. You use a Thread if you want to run in parallel. If you want both, then you use a Service that launches a Thread.
From what I'm reading (you don't want the Thread to continue after the Activity is finished), you want a Thread and not a Service.
A service can run in isolation (while your app is not necessarily running). A thread can be spun off from either your app itself, or a service.

Guarantee immediate start of parallel threads/tasks/whatever

I will use "Process" to refer to the work that is going to happen in parallel, and "enqueue" to refer to whatever process is going to be used to initiate that process (whether that be Task.Run, ThreadPool.QUWI, new Thread() ... whatever).
We have a performance sensitive program that spawn multiple parallel processes to gather data.
We're having issues with the spawning, that the processes are not beginning immediately.
Specifically, if we prepare a process, start a timer, enqueue the process, and check the timer as the very first action in the process ... then we see that the time delay occasionally stretches into 100s or even 1000s of milliseconds.
Given that the process itself is supposed to only run for 3-10 seconds, having a 2sec delay between enqueuing and activation of the process is a major issue.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Currently our implementations started using TP.QUWI, and then we move to using Task.Run.
Our initial investigation lead us to the Thread-Creation-Strategy used by Threadpool and using ThreadPool.SetMinThreads(), so we're pursuing that angle, to see if that will completely resolve the issue.
But is there another change/approach that we should be looking at, if our goal is to have the process start immediately after enqueuing?
Taken from here (I strongly suggest you have a read up):
Seems as though what you want can be achieved by overridding the default task scheduler.... scarey...
You can't assume that all parallel tasks will immediately run. Depending on the current work load and system configuration, tasks might be scheduled to run one after another, or they might run at the same time. For more information about how tasks are scheduled, see the section, "The Default Task Scheduler," later in this chapter.
Creating Tasks with Custom Scheduling
You can customize the details of how tasks in .NET are scheduled and run by overriding the default task scheduler that's used by the task factory methods. For example, you can provide a custom task scheduler as an argument to one of the overloaded versions of the TaskFactory.StartNew method.
There are some cases where you might want to override the default scheduler. The most common case occurs when you want your task to run in a particular thread context... Other cases occur when the load-balancing heuristics of the default task scheduler don't work well for your application. For more information, see the section, "Thread Injection," later in this chapter.
Unless you specify otherwise, any new tasks will use the current task scheduler...
You can implement your own task scheduler class. For more information, see the section, "Writing a Custom Task Scheduler," later in this chapter.
Thread Injection
The .NET thread pool automatically manages the number of worker threads in the pool...
Have a read of this SO post "replacing the task scheduler in c sharp with a custom built one"

parallel execution freezes service

I have a problem understand how Workflow Scheduler works, my architecture is the follow: I have several operations that call asyncronously a service from UI, it inizialize a new WorkflowApplication and calls Run() method, than it take some time to accomplish the operation, it goes through some steps and than an activity does the big work
I understand the workflow scheduler can process one workflow instance at time, but while workflows are running that seems to "freeze" my entire website, I can't access any other service, it become slow until all workflows finish. (I have also tried to call service just once and start all workflow inside it but the behavior is pretty the same)
Could someone help me understand that? There is some way to avoid this?
First impression is that there is thread starvation, or something similar with another resource contention, going on.
Are you using a WorkflowApplication or a WorkflowServiceHost to execute your workflow? I believe the first but it isn't quite clear in your question.
If you are using a WorkflowApplication: Are you setting the SynchronisationContext and are you waiting for the workflow to complete before finishing the request?
How many workflows are you starting and approximation how many ASP.NET requests are there being executed?

Categories