void LibEventServer::stop() { Lock lock(m_mutex); if (getStatus() != RunStatus::RUNNING || m_server == nullptr) return; #define SHUT_FBLISTEN 3 /* * Modifications to the Linux kernel to support shutting down a listen * socket for new connections only, but anything which has completed * the TCP handshake will still be accepted. This allows for un-accepted * connections to be queued and then wait until all queued requests are * actively being processed. */ if (RuntimeOption::ServerShutdownListenWait > 0 && m_accept_sock != -1 && shutdown(m_accept_sock, SHUT_FBLISTEN) == 0) { int noWorkCount = 0; for (int i = 0; i < RuntimeOption::ServerShutdownListenWait; i++) { // Give the acceptor thread time to clean out all requests Logger::Info( "LibEventServer stopping port %d: [%d/%d] a/q/e %d/%d/%d", m_port, i, RuntimeOption::ServerShutdownListenWait, getActiveWorker(), getQueuedJobs(), getLibEventConnectionCount()); sleep(1); // If we're not doing anything, break out quickly noWorkCount += (getQueuedJobs() == 0 && getActiveWorker() == 0); if (RuntimeOption::ServerShutdownListenNoWork > 0 && noWorkCount >= RuntimeOption::ServerShutdownListenNoWork) break; if (getLibEventConnectionCount() == 0 && getQueuedJobs() == 0 && getActiveWorker() == 0) break; } Logger::Info("LibEventServer stopped port %d: a/q/e %d/%d/%d", m_port, getActiveWorker(), getQueuedJobs(), getLibEventConnectionCount()); } // inform LibEventServer::onRequest() to stop queuing setStatus(RunStatus::STOPPING); // stop JobQueue processing m_dispatcher.stop(); // stop event loop setStatus(RunStatus::STOPPED); if (write(m_pipeStop.getIn(), "", 1) < 0) { // an error occured but we're in shutdown already, so ignore } m_dispatcherThread.waitForEnd(); // wait for the timeout thread to stop m_timeoutThreadData.stop(); m_timeoutThread.waitForEnd(); evhttp_free(m_server); m_server = nullptr; }
void ProxygenServer::forceStop() { Logger::Info("%p: forceStop ProxygenServer port=%d, enqueued=%d, conns=%d", this, m_port, m_enqueuedCount, getLibEventConnectionCount()); m_httpServerSocket.reset(); m_httpsServerSocket.reset(); // Drops all open connections if (m_httpAcceptor && m_httpAcceptor->getState() < Acceptor::State::kDone) { m_httpAcceptor->forceStop(); } if (m_httpsAcceptor && m_httpAcceptor->getState() < Acceptor::State::kDone) { m_httpsAcceptor->forceStop(); } // No more responses coming from worker threads stopConsuming(); Logger::Verbose("%p: Stopped response queue consumer port=%d", this, m_port); // The worker should exit gracefully m_worker.stopWhenIdle(); Logger::Verbose("%p: i/o thread notified to stop port=%d", this, m_port); // Aaaand we're done - oops not thread safe. Does it matter? setStatus(RunStatus::STOPPED); HttpServer::MarkShutdownStat(ShutdownEvent::SHUTDOWN_DONE); for (auto listener: m_listeners) { listener->serverStopped(this); } }
void ProxygenServer::timeoutExpired() noexcept { Logger::Info("%p: shutdown timer expired for ProxygenServer port=%d, " "state=%d, a/q/e %d/%d/%d", this, m_port, (int)m_shutdownState, getActiveWorker(), getQueuedJobs(), getLibEventConnectionCount()); // proceed to next shutdown phase doShutdown(); }
void ProxygenServer::reportShutdownStatus() { if (m_port != RuntimeOption::ServerPort) return; if (getStatus() == RunStatus::STOPPED) return; Logger::FInfo("Shutdown state={}, a/q/e/p {}/{}/{}/{}, RSS={}Mb", static_cast<int>(m_shutdownState), getActiveWorker(), getQueuedJobs(), getLibEventConnectionCount(), m_pendingTransports.size(), Process::GetProcessRSS(getpid())); m_worker.getEventBase()->runAfterDelay([this]{reportShutdownStatus();}, 500); }
void ProxygenServer::stopVM() { m_shutdownState = ShutdownState::STOPPING_VM; // we can't call m_dispatcher.stop() from the event loop, because it blocks // all I/O. Spawn a thread to call it and callback when it's done. std::thread vmStopper([this] { purge_all(); Logger::Info("%p: Stopping dispatcher port=%d", this, m_port); m_dispatcher.stop(); Logger::Info("%p: Dispatcher stopped port=%d. conns=%d", this, m_port, getLibEventConnectionCount()); m_worker.getEventBase()->runInEventBaseThread([this] { vmStopped(); }); }); vmStopper.detach(); }
bool ProxygenServer::canAccept() { return (RuntimeOption::ServerConnectionLimit == 0 || getLibEventConnectionCount() < RuntimeOption::ServerConnectionLimit); }