vibe.d
vibe.d copied to clipboard
Interrupting task causes 'bad' connection to go back to pool
In an attempt to implement timeout for requestHTTP
, I wrote the function below:
T timeout(T)(T delegate() expr, Duration period)
{
auto event = createManualEvent();
bool finishedNormally = false;
Exception ex;
T result;
auto task = runTask({
try { result = expr(); finishedNormally = true; }
catch (Exception e) { ex = e; }
finally { event.emit(); }
});
event.wait(period, 0);
if (!finishedNormally)
task.interrupt();
if (ex !is null) throw ex;
if (finishedNormally) return result;
else throw new Exception("task interrupted");
}
I expected this to work correctly, however, as evidenced by the piece of code below, this is buggy:
import vibe.d;
void main()
{
runTask({
auto settings = new HTTPServerSettings();
settings.port = 9889;
listenHTTP(
settings,
(HTTPServerRequest req, HTTPServerResponse res)
{
sleep(5.seconds); // comment this for things to work correctly
res.writeJsonBody(req.query["q"]);
}
);
});
runTask({
timeout({ makeRequest("first_request"); return true; }, 2.seconds);
});
setTimer(6.seconds, {
makeRequest("second_request");
});
runEventLoop();
}
void makeRequest(string query)
{
auto res = requestHTTP("http://localhost:9889/?q=%s".format(query));
scope(exit) res.dropBody();
auto response = res.readJson().to!string();
if (response != query)
logWarn("unexpected response! Got '%s' while expecting '%s'.", response, query);
else
logInfo("everything is working correctly");
}
The code above creates a server that responds with the request's query param q
after 5 seconds. However, the client timeouts after 2 seconds. And sends another request after 6 seconds from the start. The problem shows when the response from the first request is received by the second request. I believe that this is due to the connection being returned to the pool and reused by the second request.
The output from the code above is:
Listening for requests on http://[::]:9889/
Failed to listen on 0.0.0.0:9889
Task terminated with uncaught exception: Task interrupted.
unexpected response! Got 'first_request' while expecting 'second_request'.
Is this correct behavior from vibe.d and timeout
should be implemented differently? Or in this case, because the connection wasn't finalized correctly, it shouldn't be returned to the pool and reused?
Any advice or possible workaround?