diff --git a/hphp/runtime/base/server/http_request_handler.cpp b/hphp/runtime/base/server/http_request_handler.cpp index 2a261a721..3333ee96a 100644 --- a/hphp/runtime/base/server/http_request_handler.cpp +++ b/hphp/runtime/base/server/http_request_handler.cpp @@ -32,6 +32,7 @@ #include "hphp/runtime/base/time/datetime.h" #include "hphp/runtime/debugger/debugger.h" #include "hphp/util/alloc.h" +#include "hphp/util/service_data.h" namespace HPHP { /////////////////////////////////////////////////////////////////////////////// @@ -43,7 +44,10 @@ AccessLog HttpRequestHandler::s_accessLog( &(HttpRequestHandler::getAccessLogThreadData)); HttpRequestHandler::HttpRequestHandler() - : m_pathTranslation(true) { + : m_pathTranslation(true), + m_requestTimedOutOnQueue(ServiceData::createTimeseries( + "requests_timed_out_on_queue", + {ServiceData::StatsType::COUNT})) { } void HttpRequestHandler::sendStaticContent(Transport *transport, @@ -129,6 +133,24 @@ void HttpRequestHandler::handleRequest(Transport *transport) { transport->sendString("Not Found", 404); return; } + + // don't serve the request if it's been sitting in queue for longer than our + // allowed request timeout. + int requestTimeoutSeconds = (vhost->getRequestTimeoutSeconds() > 0 ? + vhost->getRequestTimeoutSeconds() : + RuntimeOption::RequestTimeoutSeconds); + if (requestTimeoutSeconds > 0) { + timespec now; + gettime(CLOCK_MONOTONIC, &now); + const timespec& queueTime = transport->getQueueTime(); + + if (gettime_diff_us(queueTime, now) > requestTimeoutSeconds * 1000000) { + transport->sendString("Service Unavailable", 503); + m_requestTimedOutOnQueue->addValue(1); + return; + } + } + ServerStats::StartRequest(transport->getCommand().c_str(), transport->getRemoteHost(), vhost->getName().c_str()); diff --git a/hphp/runtime/base/server/http_request_handler.h b/hphp/runtime/base/server/http_request_handler.h index 82853d96d..dd9bff385 100644 --- a/hphp/runtime/base/server/http_request_handler.h +++ b/hphp/runtime/base/server/http_request_handler.h @@ -26,6 +26,11 @@ namespace HPHP { class SourceRootInfo; class RequestURI; + +namespace ServiceData { +class ExportedTimeSeries; +} + /////////////////////////////////////////////////////////////////////////////// class HttpRequestHandler : public RequestHandler { @@ -43,6 +48,7 @@ public: private: bool m_pathTranslation; + ServiceData::ExportedTimeSeries* m_requestTimedOutOnQueue; bool handleProxyRequest(Transport *transport, bool force); void sendStaticContent(Transport *transport, const char *data, int len, diff --git a/hphp/runtime/base/server/virtual_host.cpp b/hphp/runtime/base/server/virtual_host.cpp index 252a7c1ec..d6728c837 100644 --- a/hphp/runtime/base/server/virtual_host.cpp +++ b/hphp/runtime/base/server/virtual_host.cpp @@ -136,6 +136,10 @@ void VirtualHost::setRequestTimeoutSeconds() const { } } +int VirtualHost::getRequestTimeoutSeconds() const { + return m_runtimeOption.requestTimeoutSeconds; +} + VirtualHost::VirtualHost() : m_disabled(false) { Hdf empty; initRuntimeOption(empty); diff --git a/hphp/runtime/base/server/virtual_host.h b/hphp/runtime/base/server/virtual_host.h index 23be7dae2..645640600 100644 --- a/hphp/runtime/base/server/virtual_host.h +++ b/hphp/runtime/base/server/virtual_host.h @@ -42,6 +42,7 @@ public: void init(Hdf vh); void addAllowedDirectories(const std::vector& dirs); void setRequestTimeoutSeconds() const; + int getRequestTimeoutSeconds() const; const std::string &getName() const { return m_name;} const std::string &getPathTranslation() const { return m_pathTranslation;}