Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c# run an async task in background when parent returns

I am writing a MVC5 app that has a controller with a function say Method1

I have a third party function that is async Task, let's call it DoMethodAsync (it essentially makes a POST call).

I want to call it right before returning from Method1 but I don't really care about the result of the async task, if it fails, it fails. How can I fire and forget and have it execute in the background so that it does not block the controller from responding to other requests?

How can I ensure that DoMethodAsync is only executed after Method1 has returned?

like image 397
WindowsMaker Avatar asked Mar 01 '16 19:03

WindowsMaker


People also ask

What C is used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

What is the full name of C?

In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr.

What is C in C language?

What is C? C is a general-purpose programming language created by Dennis Ritchie at the Bell Laboratories in 1972. It is a very popular language, despite being old. C is strongly associated with UNIX, as it was developed to write the UNIX operating system.

Is C language easy?

C is a general-purpose language that most programmers learn before moving on to more complex languages. From Unix and Windows to Tic Tac Toe and Photoshop, several of the most commonly used applications today have been built on C. It is easy to learn because: A simple syntax with only 32 keywords.


2 Answers

I don't really care about the result of the async task, if it fails, it fails.

Really? Just asking, because this is an extremely rare use case.

How can I fire and forget and have it execute in the background so that it does not block the controller from responding to other requests?

I have a blog post that looks into various approaches to "fire and forget" tasks on ASP.NET.

You don't want to just call the method and ignore the returned task, because that method will inherit the request context for the initiating request. Then after the request is completed, the request context is disposed, and that method can end up in an "interesting" place - some things will work, but others will not.

So, the minimum viable solution is to wrap it in Task.Run:

var _ignored = Task.Run(() => DoMethodAsync());

However, note that ASP.NET is completely unaware of this "extra operation". If you want DoMethodAsync to have more of a chance of actually executing to completion, then you'll want to register it with the ASP.NET runtime, either using HostingEnvironment.QueueBackgroundWorkItem (4.5.2+) or my own BackgroundTaskManager.Run (4.5.0/4.5.1).

Also note that none of these options will guarantee that DoMethodAsync will run to completion; they just give you a "best effort." For a truly reliable system, you'd need a proper distributed architecture, i.e., reliable storage with an independent processor.

like image 182
Stephen Cleary Avatar answered Oct 14 '22 02:10

Stephen Cleary


I know this is old, but after hours of searching and trying different things myself, I came across this thread. Combining some info here with other resource, I was able to implement what I wanted which I believe is the same thing the OP wanted.

I wanted to call a URL like /API/Start and I wanted that URL to instantly return a view that said "Thank you for starting, check back later". However it needed to then simply kick off a background job.

This is with MVC 5 so not sure if it makes a difference, but...

Side Note: To see this in action, use 2 URL's /Default/Index <-- will report back ~5 seconds /Default/IndexAsync <-- will report back ~0 seconds (well sort of .. you'll see)

public class DefaultController : Controller
{

    // GET: Sync
    public ActionResult Index()
    {
        System.Diagnostics.Stopwatch myStopwatch = new System.Diagnostics.Stopwatch();
        myStopwatch.Start();
        DoTask();
        myStopwatch.Stop();

        ViewBag.Message = ($"Process took {myStopwatch.Elapsed.TotalSeconds.ToString()}");
        return View("Index");
    }

    // GET: Async
    public ActionResult IndexAsync()
    {
        System.Diagnostics.Stopwatch myStopwatch = new System.Diagnostics.Stopwatch();
        myStopwatch.Start();
        Task.Factory.StartNew(DoTaskAsync);
        myStopwatch.Stop();

        ViewBag.Message = ($"Process took {myStopwatch.Elapsed.TotalSeconds.ToString()}");
        return View("Index");
    }

    // "the Sync Task"
    private void DoTask()
    {
        System.Diagnostics.Debug.Print($"DoTask Started at {DateTime.Now.ToString()}");
        System.Threading.Thread.Sleep(5000);
        System.Diagnostics.Debug.Print($"DoTask Finished at {DateTime.Now.ToString()}");
    }

    // "the Async Task"
    private async Task DoTaskAsync()
    {
        System.Diagnostics.Debug.Print($"DoTaskAsync Started at {DateTime.Now.ToString()}");
        System.Threading.Thread.Sleep(5000);
        System.Diagnostics.Debug.Print($"DoTaskAsync Finished at {DateTime.Now.ToString()}");
    }      

}
like image 21
da_jokker Avatar answered Oct 14 '22 03:10

da_jokker