Why ASP.NET kills my background thread?

后端 未结 4 1500
日久生厌
日久生厌 2020-12-14 11:21

I have the following code in my codebehind (aspx.cs):

protected void button1_Click(object sender, EventArgs e)
{
    new Thread(delegate() {
        try
             


        
相关标签:
4条回答
  • 2020-12-14 11:44

    ASP.NET worker process unloads virtual applications if there are no requests hitting aspx/asmx pages to save memory on IIS.

    IIS is kicking out your thread because it is not a background thread.

    On IIS there is this option:

    <processModel
    enable="true"
    timeout="Infinite"
    idleTimeout="Infinite"
    shutdownTimeout="0:00:05"
    requestLimit="Infinite"
    requestQueueLimit="5000"
    restartQueueLimit="10"
    memoryLimit="60"
    webGarden="false"
    cpuMask="0xffffffff"
    userName="machine"
    password="AutoGenerate"
    logLevel="Errors"
    clientConnectedCheck="0:00:05"
    comAuthenticationLevel="Connect"
    comImpersonationLevel="Impersonate"
    responseRestartDeadlockInterval="00:09:00"
    responseDeadlockInterval="00:03:00"
    maxWorkerThreads="20"
    maxIoThreads="20"
    />
    
    0 讨论(0)
  • 2020-12-14 11:48

    Ok, so after 48 hours of experimenting here's what I found:

    1. It's fine to run background threads in ASP.NET _MVC_

    If you're on MVC - just start your threads as normal, they won't be aborted after the current request ends:

    //MVC - works just fine
    public ActionResult ThreadTest()
    {
        new Thread(delegate() {
            try
            {
                System.Threading.Thread.Sleep(10000);
            }
            catch(Exception ex)
            {
                //no exception will be thrown
            }
        }).Start();
        return Content("ok");
    }
    

    2. For Web-Forms - use BackgroundWorker in combination with "Async" page attribute

    I learned that with webforms you can't use:

    • new Thread().Start(); //not working

    • ThreadPool.QueueUserWorkItem //not working

    • Action.BeginInvoke //not working

    • A bunch of other things - all not working

    Here's what you need to do:

    1) Mark your page as "async" in .aspx (this will tell ASP.NET to inherit the page from IAsyncHandler)

    <%@ Page language="c#" Async="true" %>
    

    2) Use BackgroundWorker in .aspx.cs

    protected void button1_Click(object sender, EventArgs e)
    {
        var bg = new BackgroundWorker();
        bg.DoWork += delegate
        {
            try
            {
                Thread.Sleep(10000); //do nothing for 10 seconds
            }
            catch (Exception ex)
            {
                //no excpeiton is thrown
            }
    
        };
        bg.RunWorkerAsync();
    }
    

    3. If you're on .NET 4.5.2 or higher - simply use HostingEnvironment.QueueBackgroundWorkItem

    "The HostingEnvironment.QueueBackgroundWorkItem method lets you schedule small background work items. ASP.NET tracks these items and prevents IIS from abruptly terminating the worker process until all background work items have completed. This method can't be called outside an ASP.NET managed app domain."

    Kudos to @danny-tuppeny for this last one

    0 讨论(0)
  • 2020-12-14 11:51

    The end of a response usually does kill a thread, yes. If you call Response.End you can even see that IIS throws a ThreadAbortedException to immediately terminate the thread. In general, you shouldn't be performing any long running tasks in IIS, especially not on a Task or Background Thread. For more information about why you should avoid this, as well as how you can force IIS to handle your long running operations (if you really must) check out these links:

    Stack Overflow Question on long running jobs in IIS

    The dangers of background tasks in asp.net

    0 讨论(0)
  • 2020-12-14 12:02

    ASP.NET WebForms

    Providing another solution: you don't need to set your page with the async property. The following code will work fine:

    new Thread
    (
        delegate()
        {
            try
            {
                MyMethod(myVar);
            }
            catch (Exception ex)
            {
                // handle
            }
        }
    )
    {
        IsBackground = true
    }.Start();
    

    In this code, IsBackground = true is what prevents the thread to be aborted when the request finishes.

    0 讨论(0)
提交回复
热议问题