我遇到了一个非常奇怪的场景,我使用HTTP构建的服务器应用程序总是开始错误地响应客户端请求。服务器是一个位于数据库顶部的简单程序,允许通过从查询/请求层次结构发送序列化对象来查询该数据库。
我使用F#编写的简单可重用HTTP服务器,使用邮箱处理器异步接收和服务请求:
type public HttpAgent (port:int, handler:System.Action<HttpListenerContext>) =
let tokenSource = new CancellationTokenSource()
let processorBody (mailbox: MailboxProcessor<HttpListenerContext>) =
async {
while true do
let! context = mailbox.Receive()
Async.Start(async { handler.Invoke(context) } )
}
let agent = new MailboxProcessor<HttpListenerContext>(processorBody, tokenSource.Token)
member public x.Start () = // Starts the server listening on the specified port
agent.Start()
let server = async {
use listener = new HttpListener()
listener.Prefixes.Add(String.Format("http://*:{0}/", port))
listener.Start()
while true do
let! context = listener.AsyncGetContext()
agent.Post(context)
}
do Async.Start(server, cancellationToken = tokenSource.Token)
member public x.Stop () = // Stops the Agent server
tokenSource.Cancel()
正如您所看到的,为了运行服务器,您只需要为此类型提供一个Action,就可以为邮箱异步接收的每个请求上下文调用一个Action。
位于数据库顶部的实际服务器如下所示:
Func<QueryRequest, QueryResponse> tryQueryLookup = (request) => {
if (request is RequestTypeA) {
// attempt to retrieve from database
} else if (request is RequestTypeB) {
// attempt to retreive from database
}
// ... etc
if (querySuccessful) {
return new QueryResponse(databaseResults);
} else {
return new QueryResponse("Error");
}
}
Action<HttpListenerContext> requestParser = (context) => {
Action<QueryResponse> writeResponse = (response) => {
try {
using (StreamWriter streamWriter = new StreamWriter(context.Response.OutputStream)) {
streamWriter.Write(response.ToXml());
}
} catch (Exception ex) {
// write error message to event log
}
};
try {
QueryRequest request = null;
string requestBytes = new StreamReader(context.Request.InputStream).ReadToEnd();
request = requestBytes.FromXml<QueryRequest>();
writeResponse(tryQueryLookup(request));
} catch (Exception ex) {
writeResponse(new QueryResponse("Error"));
}
};
m_HttpAgent = new HttpAgent(port, requestParser);
m_HttpAgent.Start()
这项服务在我们的开发环境中已经运行了好几个星期了,但是今天我遇到了一个错误,其中一个请求返回了与它无关的响应 - 它只能来自不同的请求服务器作为请求类型完全不同。
我已经设置了一个测试控制台应用程序,它为每个查询类型启动一个不同的线程,并无限地向服务发出请求。成千上万的这些成功返回,但最终总会收到来自服务器的消息,该消息是响应来自其他线程之一的请求类型而生成的。有时,服务器似乎进入故障状态,其中所有请求都将返回与交叉类型相对应的消息。
我想知道是否存在一些我遗漏的明显线程问题或者我不知道的HTTPListenerContext的行为,因为代码似乎通过在requestParser中使用闭包来保持每个HTTPListenerContext被隔离