Prevent IIS from killing a Task before it ends

前端 未结 4 988
礼貌的吻别
礼貌的吻别 2020-12-31 15:28

I\'m building a Logging library that stores everything on an Azure table. Writing to that table obviously takes a lot of time (never more than 1 sec, but it\'s still too muc

相关标签:
4条回答
  • 2020-12-31 15:58

    Sorry for not adding this as a comment, I don't have enough rep.

    https://msdn.microsoft.com/en-us/library/system.web.hosting.iregisteredobject(v=vs.110).aspx

    Applications can have only one instance of a registered type.

    This seems to indicate that Gervasio Marchand's accepted answer is somewhat incorrect, as each call to his static helper method creates a new IISNotifier, which is an IRegisteredObject.

    0 讨论(0)
  • 2020-12-31 16:00

    The information is not enough but I suspect it may be related to GC and references if it works when you wait fo the task. For your purpose, a better way is to use ETW (EventProvider) and set the ActivityId for each request. Simply configure an ETW session can redirect all the messages to a file. You can show the ActivityId (a Guid) to the end user.

    0 讨论(0)
  • 2020-12-31 16:12

    Thanks to Damian Schenkelman and that blog post of Phil Haack, I figured out the problem and the solution. The problem is that IIS reuses the threads when it needs to handle new requests. And as it doesn't know that my task is doing some work, it reuses that thread (which makes sense). Then, I just have to notify IIS that I'm using that thread and that it can't be reused (so, it has to either reuse another thread, create a new one, or make it wait). I ended up using my own TaskFactory that handles the task creation, and automatically registers a notifier in IIS. For completeness, to help some other folk with the same issue as me, and to read another suggestions, here's what I've done

    public class IISNotifier : IRegisteredObject
    {
        public void Stop(bool immediate)
        {
            // do nothing, I only run tasks if I know that they won't
            // take more than a few seconds.
        }
    
        public void Started()
        {
            HostingEnvironment.RegisterObject(this);
        }
    
        public void Finished()
        {
            HostingEnvironment.UnregisterObject(this);
        }
    }
    

    And then

    public class IISTaskFactory
    {
        public static Task StartNew(Action act)
        {
            IISNotifier notif = new IISNotifier();
            notif.Started();
            return Task.Factory.StartNew(() => {
                act.Invoke();
                notif.Finished();
            });
        }
    }
    

    Now, when I want to start a the log task I just do

    return new LogResult(id, IISTaskFactory.StartNew(() => 
        DoLogInAzure(account, id, exception, request))
    );
    

    You can see (and download the code) at https://github.com/gmc-dev/IISTask

    0 讨论(0)
  • 2020-12-31 16:17

    This post from Phil Hack talks about running background tasks in an ASP.NET application.

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