停止自托管owin服务器时完成当前的请求服务器、owin

2023-09-06 15:01:06 作者:身体归宿

我OWIN服务器的控制台应用程序的一部分。你可以在这里看到的主要方法:

I have OWIN server as part of console app. You can see the main method here:

class Program
{
    public static ManualResetEventSlim StopSwitch = new ManualResetEventSlim();

    static void Main(string[] args)
    {
        Console.CancelKeyPress += (s, a) =>
        {
            a.Cancel = true;
            StopSwitch.Set();
        };

        using (WebApp.Start<Startup>("http://+:8080/"))
        {
            Console.WriteLine("Server is running...");
            Console.WriteLine("Press CTRL+C to stop it.");
            StopSwitch.Wait();
            Console.WriteLine("Server is stopping...");
        }

        Console.ReadKey();
        Console.WriteLine("Server stopped. Press any key to close app...");
    }
}

在处理请求是长一点,并在同一时间的用户presses CTRL + C停止请求处理立即停止,并响应不发送应用程序。是否有可能改变这种行为?我想拒绝所有新的请求,但等到它正在处理的请求完成,之后停止服务器。

When processing of the request is little bit longer and in the same time user presses CTRL+C to stop the application the request processing is stopped immediately and response is not sent. Is it possible to change this behavior? I would like to refuse all new requests but wait until the requests which are currently processing are done and stop server after that.

我最初的想法是创建OWIN中间件将继续要求这是目前处理的轨道,推迟停止动作,直到一切都做。中间件也要在停止相短路的所有请求。但是,这种解决方案听起来不错,我不是。

My initial idea is to create OWIN middleware which will keep track of requests which are currently processing and postpone the stop action until everything is done. Middleware would also short-circuit all requests during the stopping phase. But this solution doesn't sound good to me.

推荐答案

我与中间件的建议的方法结束:

I ended with the suggested approach with the middleware:

public class ShutDownMiddleware
{
    private readonly Func<IDictionary<string, object>, Task> next;
    private static int requestCount = 0;
    private static bool shutDownStateOn = false;

    public static void ShutDown()
    {
        shutDownStateOn = true;
    }

    public static int GetRequestCount()
    {
        return requestCount;
    }

    public ShutDownMiddleware(Func<IDictionary<string, object>, Task> next)
    {
        this.next = next;
    }

    public async Task Invoke(IDictionary<string, object> environment)
    {
        if (shutDownStateOn)
        {
            environment["owin.ResponseStatusCode"] = HttpStatusCode.ServiceUnavailable;
            return;
        }

        Interlocked.Increment(ref requestCount);
        try
        {
            await next.Invoke(environment);
        }
        finally
        {
            Interlocked.Decrement(ref requestCount);
        }
    }
}

这是登记在管道中的第一个中间件和程序的主要方法,我可以用它是这样的:

This is registered as a first middleware in the pipeline and in the main method of program I can use it like this:

public class Program
{
    public static ManualResetEventSlim StopSwitch = new ManualResetEventSlim();

    static void Main(string[] args)
    {
        Console.CancelKeyPress += (s, a) =>
        {
            a.Cancel = true;
            StopSwitch.Set();
        };

        using (WebApp.Start<Startup>("http://+:8080/"))
        {
            Console.WriteLine("Server is running...");
            Console.WriteLine("Press CTRL+C to stop it.");
            StopSwitch.Wait();
            Console.WriteLine("Server is stopping...");
            ShutDownMiddleware.ShutDown();
            while (ShutDownMiddleware.GetRequestCount() != 0)
            {
                Thread.Sleep(TimeSpan.FromSeconds(1));
            }
        }
    }
}

我也发现了这一点:的https://katanaproject.$c$cplex.com/workitem / 281 他们谈论类似的做法。

I also found this: https://katanaproject.codeplex.com/workitem/281 They are talking about similar approach.