杀死一个任务之前结束prevent IIS任务、结束、IIS、prevent

2023-09-03 11:19:30 作者:你是我绕过人间山河,才遇到的人间烟火。下面小编为您带来从诗词

我要建一个存储都在一个Azure的表中的记录库。编写该表显然需要花费大量的时间(从来没有超过1秒,但它仍然太多,使用户等待),这样登录方法返回一个LogResult实例,这里的类

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 much to make the user wait), so Log method returns a LogResult instance, here's the class

public class LogResult
{
    public string Id { get; set; }
    public Task LoggingTask { get; set; }

    public LogResult(string id, Task task)
    {
        Id = id;
        LoggingTask = task;
    }
}

和这里是如何的日志方法完成

And here is how the Log method finishes

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

为了让呼叫者等待它完成(如果它是一个控制台应用程序,例如)的选项。我现在面临的问题是,IIS的不应该的等待它返回用户的响应之前...如果我不等待它,IIS不的总是的执行任务。我们的想法是向用户显示一条消息,......如果您联系我们,一定要提到你的发行数量,XXX,并没有让他等待日志条目已被写入。

To give the caller the option of waiting for it to complete (if it's a console app, for instance). The issue I'm facing is that IIS shouldn't wait for it before returning the user the response... and if I don't wait for it, IIS doesn't always execute the task. The idea is to show the user a message "... If you contact us, be sure to mention your issue number, XXX" and don't make him wait until the log entry has been written.

有没有办法强制IIS等到任务完成,即使它返回的响应?我想我可能需要codeA的Windows服务的任务的要求不同步,但它看起来像一个大量的工作只是增加一个日志条目......特别是如果我能强制IIS等待吧。

Is there any way to force IIS to wait until the task finishes, even after it returned the response? I'm thinking I may need to code a Windows Service that takes the request asynchronously, but it looks like a lot of work just to add a log entry... specially if I can force IIS to wait for it.

感谢您的想法!

推荐答案

由于达米安Schenkelman和菲尔哈克的那个博客后,我想通了的问题和解决方案。问题是,IIS重用线程时,它需要处理新的请求。而且,因为它不知道我的任务是做了一些工作,它重新使用该线程(这是有意义的)。然后,我只是来通知我使用的线程IIS,它不能重用(因此,它必须选择利用另一个线程,创建一个新的,或使其等待)。最后我用我自己的TaskFactory处理任务创建,并自动登记在IIS中的通知。为了完整起见,以帮助其他人使用相同的问题,因为我,读另外一个建议,这是我做了

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);
    }
}

然后

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))
);

您可以看到(并下载code)在 https://github.com/gmc -dev / IISTask

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