在ServiceStack自托管服务中,如果存在待处理请求,是否可以正常关闭服务?
使用AppHost.Stop()
? (源自AppHostHttpListenerBase
)
答案 0 :(得分:4)
我认为没有内置的机制,虽然看到它会很好。我使用自己简单的Graceful关闭方法。
基本上我在first possible opportunity in the service pipeline开始每个请求之前检查一个静态bool
,IsShuttingDown
标志。 (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秒内结束,但它可以满足我的需求,大多数请求都会在很短的时间内得到处理。
由于无法访问底层连接池,因此您必须跟踪哪些连接处于活动状态。
对于这种方法,我会使用PreExecuteServiceFilter
和PostExecuteServiceFilter
来增加&amp;递减活动连接计数器。我想你会想要使用Interlocked.Increment
和Interlocked.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();
}
},
});
希望其中一些有帮助。