/** * Preferably use this method in order to start ThriftServer created for * DuplexChannel instead of the serve() method. */ void ThriftServer::startDuplex() { CHECK(configMutable()); duplexWorker_ = Cpp2Worker::create(this, serverChannel_); // we don't control the EventBase for the duplexWorker, so when we shut // it down, we need to ensure there's no delay duplexWorker_->setGracefulShutdownTimeout(std::chrono::milliseconds(0)); }
void ThriftServer::setup() { DCHECK_NOTNULL(cpp2Pfac_.get()); DCHECK_GT(nWorkers_, 0); uint32_t threadsStarted = 0; // Initialize event base for this thread, ensure event_init() is called serveEventBase_ = eventBaseManager_->getEventBase(); // Print some libevent stats VLOG(1) << "libevent " << folly::EventBase::getLibeventVersion() << " method " << folly::EventBase::getLibeventMethod(); try { // We check for write success so we don't need or want SIGPIPEs. signal(SIGPIPE, SIG_IGN); if (!observer_ && apache::thrift::observerFactory_) { observer_ = apache::thrift::observerFactory_->getObserver(); } // We always need a threadmanager for cpp2. if (!threadFactory_) { setThreadFactory( std::make_shared<apache::thrift::concurrency::PosixThreadFactory>( apache::thrift::concurrency::PosixThreadFactory::kDefaultPolicy, apache::thrift::concurrency::PosixThreadFactory::kDefaultPriority, threadStackSizeMB_ ) ); } if (saslPolicy_ == "required" || saslPolicy_ == "permitted") { if (!saslThreadManager_) { auto numThreads = nSaslPoolThreads_ > 0 ? nSaslPoolThreads_ : (nPoolThreads_ > 0 ? nPoolThreads_ : nWorkers_); saslThreadManager_ = ThreadManager::newSimpleThreadManager( numThreads, 0, /* pendingTaskCountMax -- no limit */ false, /* enableTaskStats */ 0 /* maxQueueLen -- large default */); saslThreadManager_->setNamePrefix("thrift-sasl"); saslThreadManager_->threadFactory(threadFactory_); saslThreadManager_->start(); } auto saslThreadManager = saslThreadManager_; if (getSaslServerFactory()) { // If the factory is already set, don't override it with the default } else if (FLAGS_pin_service_identity && !FLAGS_service_identity.empty()) { // If pin_service_identity flag is set and service_identity is specified // force the server use the corresponding principal from keytab. char hostname[256]; if (gethostname(hostname, 255)) { LOG(FATAL) << "Failed getting hostname"; } setSaslServerFactory([=] (folly::EventBase* evb) { auto saslServer = std::unique_ptr<SaslServer>( new GssSaslServer(evb, saslThreadManager)); saslServer->setServiceIdentity( FLAGS_service_identity + "/" + hostname); return saslServer; }); } else { // Allow the server to accept anything in the keytab. setSaslServerFactory([=] (folly::EventBase* evb) { return std::unique_ptr<SaslServer>( new GssSaslServer(evb, saslThreadManager)); }); } } if (!threadManager_) { int numThreads = nPoolThreads_ > 0 ? nPoolThreads_ : nWorkers_; std::shared_ptr<apache::thrift::concurrency::ThreadManager> threadManager(PriorityThreadManager::newPriorityThreadManager( numThreads, true /*stats*/, getMaxRequests() + numThreads /*maxQueueLen*/)); threadManager->enableCodel(getEnableCodel()); if (!poolThreadName_.empty()) { threadManager->setNamePrefix(poolThreadName_); } threadManager->start(); setThreadManager(threadManager); } threadManager_->setExpireCallback([&](std::shared_ptr<Runnable> r) { EventTask* task = dynamic_cast<EventTask*>(r.get()); if (task) { task->expired(); } }); threadManager_->setCodelCallback([&](std::shared_ptr<Runnable> r) { auto observer = getObserver(); if (observer) { observer->queueTimeout(); } }); if (!serverChannel_) { ServerBootstrap::socketConfig.acceptBacklog = listenBacklog_; // Resize the IO pool ioThreadPool_->setNumThreads(nWorkers_); ServerBootstrap::childHandler( acceptorFactory_ ? acceptorFactory_ : std::make_shared<ThriftAcceptorFactory>(this)); { std::lock_guard<std::mutex> lock(ioGroupMutex_); ServerBootstrap::group(acceptPool_, ioThreadPool_); } if (socket_) { ServerBootstrap::bind(std::move(socket_)); } else if (port_ != -1) { ServerBootstrap::bind(port_); } else { ServerBootstrap::bind(address_); } // Update address_ with the address that we are actually bound to. // (This is needed if we were supplied a pre-bound socket, or if // address_'s port was set to 0, so an ephemeral port was chosen by // the kernel.) ServerBootstrap::getSockets()[0]->getAddress(&address_); for (auto& socket : getSockets()) { socket->setShutdownSocketSet(shutdownSocketSet_.get()); socket->setMaxNumMessagesInQueue(maxNumPendingConnectionsPerWorker_); socket->setAcceptRateAdjustSpeed(acceptRateAdjustSpeed_); } // Notify handler of the preServe event if (eventHandler_ != nullptr) { eventHandler_->preServe(&address_); } } else { CHECK(configMutable()); duplexWorker_ = folly::make_unique<Cpp2Worker>(this, serverChannel_); // we don't control the EventBase for the duplexWorker, so when we shut // it down, we need to ensure there's no delay duplexWorker_->setGracefulShutdownTimeout(std::chrono::milliseconds(0)); } // Do not allow setters to be called past this point until the IO worker // threads have been joined in stopWorkers(). configMutable_ = false; } catch (std::exception& ex) { // This block allows us to investigate the exception using gdb LOG(ERROR) << "Got an exception while setting up the server: " << ex.what(); handleSetupFailure(); throw; } catch (...) { handleSetupFailure(); throw; } }