是否可以正常关闭自托管ServiceStack服务?

时间:2013-12-14 05:20:02

标签: servicestack

在ServiceStack自托管服务中,如果存在待处理请求,是否可以正常关闭服务?

使用AppHost.Stop()? (源自AppHostHttpListenerBase

1 个答案:

答案 0 :(得分:4)

我认为没有内置的机制,虽然看到它会很好。我使用自己简单的Graceful关闭方法。

基本上我在first possible opportunity in the service pipeline开始每个请求之前检查一个静态boolIsShuttingDown标志。 (RawHttpHandlers

如果此标志设置为true,则表示我不希望该服务处理更多请求,而是将http状态503 Unavailable发送给客户端。

我的优雅关闭方法只需设置IsShuttingDown标志并启动60秒的超时计时器,以便为当前处理请求提供完成时间。之后服务停止呼叫AppHost.Stop()(如果没有计时器,请参阅问题的结尾)

我的代码适用于ServiceStack v3,如果您使用该版本,则可能需要稍微修改它以使其与v4一起使用。

在你的AppHost中:

public static bool IsShuttingDown = false;

public override void Configure(Funq.Container container)
{

    // Other configuration options ...

    // Handle the graceful shutdown response
    var gracefulShutdownHandler = new CustomActionHandler((httpReq, httpRes) => {
        httpRes.StatusCode = 503;
        httpRes.StatusDescription = "Unavailable";
        httpRes.Write("Service Unavailable");
        httpRes.EndRequest();
    });

    SetConfig(new EndpointHostConfig {
        // Other EndPoint configuration options ...
        RawHttpHandlers = { httpReq => IsShuttingDown ? gracefulShutdownHandler : null }
    });

}

CustomActionHandler只是copied from here,它负责处理请求。 (v4中已包含自定义操作处理程序,因此不需要)

public class CustomActionHandler : IServiceStackHttpHandler, IHttpHandler 
{
    public Action<IHttpRequest, IHttpResponse> Action { get; set; }

    public CustomActionHandler(Action<IHttpRequest, IHttpResponse> action)
    {
        if (action == null)
            throw new Exception("Action was not supplied to ActionHandler");

        Action = action;
    }

    public void ProcessRequest(IHttpRequest httpReq, IHttpResponse httpRes, string operationName)
    {            
        Action(httpReq, httpRes);
    }

    public void ProcessRequest(HttpContext context)
    {
        ProcessRequest(context.Request.ToRequest(GetType().Name), 
            context.Response.ToResponse(),
            GetType().Name);
    }

    public bool IsReusable
    {
        get { return false; }
    }
}

我很欣赏使用计时器并不能保证所有请求都会在60秒内结束,但它可以满足我的需求,大多数请求都会在很短的时间内得到处理。

为避免使用定时器(所有连接关闭时立即关闭):

由于无法访问底层连接池,因此您必须跟踪哪些连接处于活动状态。

对于这种方法,我会使用PreExecuteServiceFilterPostExecuteServiceFilter来增加&amp;递减活动连接计数器。我想你会想要使用Interlocked.IncrementInterlocked.Decrement来确保计数的线程安全。我没有对此进行测试,可能有更好的方法。

在你的AppHost中:

public static int ConnectionCount;

// Configure Method
// As above but with additional count tracking.

    ConnectionCount = 0;

    SetConfig(new EndpointHostConfig {
        // Other EndPoint configuration options ...
        RawHttpHandlers = { httpReq => IsShuttingDown ? gracefulShutdownHandler : null },

        // Track active connection count
        PreExecuteServiceFilter = () => Interlocked.Increment(ref ConnectionCount),
        PostExecuteServiceFilter = (obj, req, res) => {
            Interlocked.Decrement(ref ConnectionCount);

            // Check if shutting down, and if there are no more connections, stop
            if(IsShuttingDown && ConnectionCount==0){
                res.EndRequest(); // Ensure last request gets their data before service stops.
                this.Stop();
            }
        },
    });

希望其中一些有帮助。