2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/runtime/server/host-health-monitor.h"
19 #include <folly/Singleton.h>
20 #include <folly/system/ThreadName.h>
22 #include "hphp/runtime/base/init-fini-node.h"
23 #include "hphp/runtime/ext/extension.h"
24 #include "hphp/util/alloc-defs.h"
25 #include "hphp/util/compatibility.h"
26 #include "hphp/util/health-monitor-types.h"
27 #include "hphp/util/logger.h"
35 struct HostHealthMonitorExtension final
: public Extension
{
36 HostHealthMonitorExtension() : Extension("hosthealthmonitor", "1.0") {}
38 void moduleLoad(const IniSetting::Map
& ini
, Hdf globalConfig
) override
{
39 Config::Bind(Enabled
, ini
, globalConfig
,
40 "HealthMonitor.EnableHealthMonitor", true);
41 Config::Bind(UpdateFreq
, ini
, globalConfig
,
42 "HealthMonitor.UpdateFreq", 1000 /* miliseconds */);
44 } s_host_health_monitor_extension
;
46 folly::Singleton
<HostHealthMonitor
> s_health_monitor
;
50 void HostHealthMonitor::addMetric(IHealthMonitorMetric
* metric
) {
51 assertx(metric
!= nullptr);
52 std::lock_guard
<std::mutex
> g(m_lock
);
53 m_metrics
.push_back(metric
);
56 void IHealthMonitorMetric::registerSelf() {
57 folly::Singleton
<HostHealthMonitor
>::try_get()->addMetric(this);
60 void HostHealthMonitor::start() {
61 if (!Enabled
|| !m_stopped
) return;
62 if (UpdateFreq
< 10) UpdateFreq
= 10;
63 if (UpdateFreq
> 10000) UpdateFreq
= 10000;
65 m_monitor_thread
= std::make_unique
<std::thread
>([] {
66 folly::setThreadName("HostHealthMonitor");
67 folly::Singleton
<HostHealthMonitor
>::try_get()->monitor();
70 // Make sure the thread is gone after hphp_process_exit(). The node
71 // is intentionally leaked.
73 [] { folly::Singleton
<HostHealthMonitor
>::try_get()->waitForEnd(); },
74 InitFiniNode::When::ProcessExit
78 void HostHealthMonitor::stop() {
79 notifyObservers(HealthLevel::Bold
);
80 std::unique_lock
<std::mutex
> guard(m_stopped_lock
);
82 m_condition
.notify_one();
85 void HostHealthMonitor::waitForEnd() {
86 if (!m_stopped
) stop();
87 if (m_monitor_thread
) {
88 m_monitor_thread
->join();
89 m_monitor_thread
.reset();
93 void HostHealthMonitor::monitor() {
94 Logger::Info("Host health monitor starts working.");
95 std::unique_lock
<std::mutex
> guard(m_stopped_lock
);
98 std::chrono::milliseconds
dura(UpdateFreq
);
100 HealthLevel newStatus
= evaluate();
101 notifyObservers(newStatus
);
102 m_condition
.wait_for(guard
, dura
, [this] { return m_stopped
; });
104 Logger::Info("Host health monitor exits.");
107 HealthLevel
HostHealthMonitor::evaluate() {
111 HealthLevel res
= HealthLevel::Bold
;
112 std::lock_guard
<std::mutex
> g(m_lock
);
113 for (auto metric
: m_metrics
) {
114 res
= std::max(res
, metric
->evaluate());
119 void HostHealthMonitor::notifyObservers(HealthLevel newStatus
) {
120 if (newStatus
!= m_status
) {
121 Logger::Warning("Health level (lower is better) changes from %d to %d.",
122 static_cast<int>(m_status
), static_cast<int>(newStatus
));
124 std::lock_guard
<std::mutex
> g(m_lock
);
125 for (auto observer
: m_observers
) {
126 observer
->notifyNewStatus(newStatus
);
128 m_status
= newStatus
;