You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by ji...@apache.org on 2016/07/02 00:02:07 UTC

[5/6] mesos git commit: Refactored HealthCheck from a binary to be a library.

Refactored HealthCheck from a binary to be a library.

Review: https://reviews.apache.org/r/49389/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/1556d9a3
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/1556d9a3
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/1556d9a3

Branch: refs/heads/master
Commit: 1556d9a3a02de4e8a90b5b64d268754f95b12d77
Parents: c097509
Author: Gilbert Song <so...@gmail.com>
Authored: Fri Jul 1 17:01:50 2016 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Fri Jul 1 17:01:50 2016 -0700

----------------------------------------------------------------------
 src/CMakeLists.txt                  |   5 +
 src/Makefile.am                     |   2 +
 src/health-check/health_checker.cpp |  92 ++++++++++
 src/health-check/health_checker.hpp | 294 +++++++++++++++++++++++++++++++
 src/health-check/main.cpp           | 229 +-----------------------
 src/launcher/executor.cpp           |  77 +++-----
 6 files changed, 418 insertions(+), 281 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/1556d9a3/src/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 996d9e6..7f22a7c 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -203,6 +203,10 @@ set(FILES_SRC
   files/files.cpp
   )
 
+set(HEALTH_CHECK_SRC
+  health-check/health_checker.cpp
+  )
+
 set(HOOK_SRC
   hook/manager.cpp
   )
@@ -409,6 +413,7 @@ set(MESOS_SRC
   ${HOOK_SRC}
   ${INTERNAL_SRC}
   ${FILES_SRC}
+  ${HEALTH_CHECK_SRC}
   ${MESSAGES_SRC}
   ${LOGGING_SRC}
   ${VERSION_SRC}

http://git-wip-us.apache.org/repos/asf/mesos/blob/1556d9a3/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index 72f8a99..52d63f2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -786,6 +786,7 @@ libmesos_no_3rdparty_la_SOURCES +=					\
   executor/executor.cpp							\
   executor/v0_v1executor.cpp						\
   files/files.cpp							\
+  health-check/health_checker.cpp						\
   hdfs/hdfs.cpp								\
   hook/manager.cpp							\
   internal/devolve.cpp							\
@@ -906,6 +907,7 @@ libmesos_no_3rdparty_la_SOURCES +=					\
   examples/utils.hpp							\
   executor/v0_v1executor.hpp						\
   files/files.hpp							\
+  health-check/health_checker.hpp						\
   hdfs/hdfs.hpp								\
   hook/manager.hpp							\
   internal/devolve.hpp							\

http://git-wip-us.apache.org/repos/asf/mesos/blob/1556d9a3/src/health-check/health_checker.cpp
----------------------------------------------------------------------
diff --git a/src/health-check/health_checker.cpp b/src/health-check/health_checker.cpp
new file mode 100644
index 0000000..585a0b5
--- /dev/null
+++ b/src/health-check/health_checker.cpp
@@ -0,0 +1,92 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef __WINDOWS__
+#include <unistd.h>
+#endif // __WINDOWS__
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <mesos/mesos.hpp>
+
+#include <process/future.hpp>
+#include <process/pid.hpp>
+#include <process/process.hpp>
+#include <process/protobuf.hpp>
+
+#include <stout/protobuf.hpp>
+
+#include "health-check/health_checker.hpp"
+
+using namespace mesos;
+
+using process::UPID;
+
+namespace mesos {
+namespace internal {
+
+using namespace process;
+
+Try<Owned<HealthChecker>> HealthChecker::create(
+    const HealthCheck& check,
+    const UPID& executor,
+    const TaskID& taskID)
+{
+  // Validate the 'HealthCheck' protobuf.
+  if (check.has_http() && check.has_command()) {
+    return Error("Both 'http' and 'command' health check requested");
+  }
+
+  if (!check.has_http() && !check.has_command()) {
+    return Error("Expecting one of 'http' or 'command' health check");
+  }
+
+  Owned<HealthCheckerProcess> process(new HealthCheckerProcess(
+      check,
+      executor,
+      taskID));
+
+  return Owned<HealthChecker>(new HealthChecker(process));
+}
+
+
+HealthChecker::HealthChecker(
+    Owned<HealthCheckerProcess> _process)
+  : process(_process)
+{
+  spawn(CHECK_NOTNULL(process.get()));
+}
+
+
+HealthChecker::~HealthChecker()
+{
+  terminate(process.get());
+  wait(process.get());
+}
+
+
+Future<Nothing> HealthChecker::healthCheck()
+{
+  return dispatch(process.get(), &HealthCheckerProcess::healthCheck);
+}
+
+} // namespace internal {
+} // namespace mesos {

http://git-wip-us.apache.org/repos/asf/mesos/blob/1556d9a3/src/health-check/health_checker.hpp
----------------------------------------------------------------------
diff --git a/src/health-check/health_checker.hpp b/src/health-check/health_checker.hpp
new file mode 100644
index 0000000..f61e80d
--- /dev/null
+++ b/src/health-check/health_checker.hpp
@@ -0,0 +1,294 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __HEALTH_CHECKER_HPP__
+#define __HEALTH_CHECKER_HPP__
+
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef __WINDOWS__
+#include <unistd.h>
+#endif // __WINDOWS__
+
+#include <iostream>
+#include <string>
+
+#include <mesos/mesos.hpp>
+
+#include <process/delay.hpp>
+#include <process/future.hpp>
+#include <process/pid.hpp>
+#include <process/process.hpp>
+#include <process/protobuf.hpp>
+#include <process/subprocess.hpp>
+
+#include <stout/duration.hpp>
+#include <stout/flags.hpp>
+#include <stout/json.hpp>
+#include <stout/option.hpp>
+#include <stout/os.hpp>
+#include <stout/protobuf.hpp>
+#include <stout/strings.hpp>
+
+#include <stout/os/killtree.hpp>
+
+#include "common/status_utils.hpp"
+
+#include "messages/messages.hpp"
+
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::map;
+using std::string;
+
+using process::UPID;
+
+namespace mesos {
+namespace internal {
+
+// Forward declarations.
+class HealthCheckerProcess;
+
+class HealthChecker
+{
+public:
+  static Try<process::Owned<HealthChecker>> create(
+      const HealthCheck& check,
+      const UPID& executor,
+      const TaskID& taskID);
+
+  ~HealthChecker();
+
+  process::Future<Nothing> healthCheck();
+
+private:
+  explicit HealthChecker(process::Owned<HealthCheckerProcess> process);
+
+  process::Owned<HealthCheckerProcess> process;
+};
+
+
+class HealthCheckerProcess : public ProtobufProcess<HealthCheckerProcess>
+{
+public:
+  HealthCheckerProcess(
+    const HealthCheck& _check,
+    const UPID& _executor,
+    const TaskID& _taskID)
+    : check(_check),
+      initializing(true),
+      executor(_executor),
+      taskID(_taskID),
+      consecutiveFailures(0) {}
+
+  virtual ~HealthCheckerProcess() {}
+
+  process::Future<Nothing> healthCheck()
+  {
+    VLOG(2) << "Health checks starting in "
+      << Seconds(check.delay_seconds()) << ", grace period "
+      << Seconds(check.grace_period_seconds());
+
+    startTime = process::Clock::now();
+
+    delay(Seconds(check.delay_seconds()), self(), &Self::_healthCheck);
+    return promise.future();
+  }
+
+private:
+  void failure(const string& message)
+  {
+    if (check.grace_period_seconds() > 0 &&
+        (process::Clock::now() - startTime).secs() <=
+          check.grace_period_seconds()) {
+      LOG(INFO) << "Ignoring failure as health check still in grace period";
+      reschedule();
+      return;
+    }
+
+    consecutiveFailures++;
+    VLOG(1) << "#" << consecutiveFailures << " check failed: " << message;
+
+    bool killTask = consecutiveFailures >= check.consecutive_failures();
+
+    TaskHealthStatus taskHealthStatus;
+    taskHealthStatus.set_healthy(false);
+    taskHealthStatus.set_consecutive_failures(consecutiveFailures);
+    taskHealthStatus.set_kill_task(killTask);
+    taskHealthStatus.mutable_task_id()->CopyFrom(taskID);
+    send(executor, taskHealthStatus);
+
+    if (killTask) {
+      // This is a hack to ensure the message is sent to the
+      // executor before we exit the process. Without this,
+      // we may exit before libprocess has sent the data over
+      // the socket. See MESOS-4111.
+      os::sleep(Seconds(1));
+      promise.fail(message);
+    } else {
+      reschedule();
+    }
+  }
+
+  void success()
+  {
+    VLOG(1) << "Check passed";
+
+    // Send a healthy status update on the first success,
+    // and on the first success following failure(s).
+    if (initializing || consecutiveFailures > 0) {
+      TaskHealthStatus taskHealthStatus;
+      taskHealthStatus.set_healthy(true);
+      taskHealthStatus.mutable_task_id()->CopyFrom(taskID);
+      send(executor, taskHealthStatus);
+      initializing = false;
+    }
+    consecutiveFailures = 0;
+    reschedule();
+  }
+
+  void _healthCheck()
+  {
+    if (check.has_http()) {
+      promise.fail("HTTP health check is not supported");
+      return;
+    }
+
+    if (!check.has_command()) {
+      promise.fail("No check found in health check");
+      return;
+    }
+
+    const CommandInfo& command = check.command();
+
+    map<string, string> environment = os::environment();
+
+    foreach (const Environment::Variable& variable,
+             command.environment().variables()) {
+      environment[variable.name()] = variable.value();
+    }
+
+    // Launch the subprocess.
+    Option<Try<process::Subprocess>> external = None();
+
+    if (command.shell()) {
+      // Use the shell variant.
+      if (!command.has_value()) {
+        promise.fail("Shell command is not specified");
+        return;
+      }
+
+      VLOG(2) << "Launching health command '" << command.value() << "'";
+
+      external = process::subprocess(
+          command.value(),
+          process::Subprocess::PATH("/dev/null"),
+          process::Subprocess::FD(STDERR_FILENO),
+          process::Subprocess::FD(STDERR_FILENO),
+          process::NO_SETSID,
+          environment);
+    } else {
+      // Use the exec variant.
+      if (!command.has_value()) {
+        promise.fail("Executable path is not specified");
+        return;
+      }
+
+      vector<string> argv;
+      foreach (const string& arg, command.arguments()) {
+        argv.push_back(arg);
+      }
+
+      VLOG(2) << "Launching health command [" << command.value() << ", "
+              << strings::join(", ", argv) << "]";
+
+      external = process::subprocess(
+          command.value(),
+          argv,
+          process::Subprocess::PATH("/dev/null"),
+          process::Subprocess::FD(STDERR_FILENO),
+          process::Subprocess::FD(STDERR_FILENO),
+          process::NO_SETSID,
+          None(),
+          environment);
+    }
+
+    CHECK_SOME(external);
+
+    if (external.get().isError()) {
+      failure("Error creating subprocess for healthcheck: " +
+              external.get().error());
+      return;
+    }
+
+    pid_t commandPid = external.get().get().pid();
+
+    process::Future<Option<int>> status = external.get().get().status();
+    status.await(Seconds(check.timeout_seconds()));
+
+    if (!status.isReady()) {
+      string msg = "Command check failed with reason: ";
+      if (status.isFailed()) {
+        msg += "failed with error: " + status.failure();
+      } else if (status.isDiscarded()) {
+        msg += "status future discarded";
+      } else {
+        msg += "status still pending after timeout " +
+               stringify(Seconds(check.timeout_seconds()));
+      }
+
+      if (commandPid != -1) {
+        // Cleanup the external command process.
+        os::killtree(commandPid, SIGKILL);
+        VLOG(1) << "Kill health check command " << commandPid;
+      }
+
+      failure(msg);
+      return;
+    }
+
+    int statusCode = status.get().get();
+    if (statusCode != 0) {
+      string message = "Health command check " + WSTRINGIFY(statusCode);
+      failure(message);
+    } else {
+      success();
+    }
+  }
+
+  void reschedule()
+  {
+    VLOG(1) << "Rescheduling health check in "
+      << Seconds(check.interval_seconds());
+
+    delay(Seconds(check.interval_seconds()), self(), &Self::_healthCheck);
+  }
+
+  process::Promise<Nothing> promise;
+  HealthCheck check;
+  bool initializing;
+  UPID executor;
+  TaskID taskID;
+  uint32_t consecutiveFailures;
+  process::Time startTime;
+};
+
+} // namespace internal {
+} // namespace mesos {
+
+#endif // __HEALTH_CHECKER_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/1556d9a3/src/health-check/main.cpp
----------------------------------------------------------------------
diff --git a/src/health-check/main.cpp b/src/health-check/main.cpp
index 4cc9dde..0b13926 100644
--- a/src/health-check/main.cpp
+++ b/src/health-check/main.cpp
@@ -23,258 +23,31 @@
 
 #include <iostream>
 #include <string>
-#include <vector>
 
 #include <mesos/mesos.hpp>
 
-#include <process/defer.hpp>
-#include <process/delay.hpp>
 #include <process/future.hpp>
-#include <process/io.hpp>
 #include <process/pid.hpp>
 #include <process/process.hpp>
 #include <process/protobuf.hpp>
-#include <process/subprocess.hpp>
 
-#include <stout/duration.hpp>
 #include <stout/flags.hpp>
 #include <stout/json.hpp>
 #include <stout/option.hpp>
-#include <stout/os.hpp>
 #include <stout/path.hpp>
 #include <stout/protobuf.hpp>
-#include <stout/strings.hpp>
 
-#include <stout/os/killtree.hpp>
-
-#include "common/status_utils.hpp"
-
-#include "messages/messages.hpp"
+#include "health-check/health_checker.hpp"
 
 using namespace mesos;
 
 using std::cout;
 using std::cerr;
 using std::endl;
-using std::map;
 using std::string;
-using std::vector;
 
 using process::UPID;
 
-namespace mesos {
-namespace internal {
-
-using namespace process;
-
-class HealthCheckerProcess : public ProtobufProcess<HealthCheckerProcess>
-{
-public:
-  HealthCheckerProcess(
-    const HealthCheck& _check,
-    const UPID& _executor,
-    const TaskID& _taskID)
-    : check(_check),
-      initializing(true),
-      executor(_executor),
-      taskID(_taskID),
-      consecutiveFailures(0) {}
-
-  virtual ~HealthCheckerProcess() {}
-
-  Future<Nothing> healthCheck()
-  {
-    VLOG(2) << "Health checks starting in "
-      << Seconds(check.delay_seconds()) << ", grace period "
-      << Seconds(check.grace_period_seconds());
-
-    startTime = Clock::now();
-
-    delay(Seconds(check.delay_seconds()), self(), &Self::_healthCheck);
-    return promise.future();
-  }
-
-private:
-  void failure(const string& message)
-  {
-    if (check.grace_period_seconds() > 0 &&
-        (Clock::now() - startTime).secs() <= check.grace_period_seconds()) {
-      LOG(INFO) << "Ignoring failure as health check still in grace period";
-      reschedule();
-      return;
-    }
-
-    consecutiveFailures++;
-    VLOG(1) << "#" << consecutiveFailures << " check failed: " << message;
-
-    bool killTask = consecutiveFailures >= check.consecutive_failures();
-
-    TaskHealthStatus taskHealthStatus;
-    taskHealthStatus.set_healthy(false);
-    taskHealthStatus.set_consecutive_failures(consecutiveFailures);
-    taskHealthStatus.set_kill_task(killTask);
-    taskHealthStatus.mutable_task_id()->CopyFrom(taskID);
-    send(executor, taskHealthStatus);
-
-    if (killTask) {
-      // This is a hack to ensure the message is sent to the
-      // executor before we exit the process. Without this,
-      // we may exit before libprocess has sent the data over
-      // the socket. See MESOS-4111.
-      os::sleep(Seconds(1));
-      promise.fail(message);
-    } else {
-      reschedule();
-    }
-  }
-
-  void success()
-  {
-    VLOG(1) << "Check passed";
-
-    // Send a healthy status update on the first success,
-    // and on the first success following failure(s).
-    if (initializing || consecutiveFailures > 0) {
-      TaskHealthStatus taskHealthStatus;
-      taskHealthStatus.set_healthy(true);
-      taskHealthStatus.mutable_task_id()->CopyFrom(taskID);
-      send(executor, taskHealthStatus);
-      initializing = false;
-    }
-    consecutiveFailures = 0;
-    reschedule();
-  }
-
-  void _healthCheck()
-  {
-    if (check.has_http()) {
-      promise.fail("HTTP health check is not supported");
-      return;
-    }
-
-    if (!check.has_command()) {
-      promise.fail("No check found in health check");
-      return;
-    }
-
-    const CommandInfo& command = check.command();
-
-    map<string, string> environment = os::environment();
-
-    foreach (const Environment::Variable& variable,
-             command.environment().variables()) {
-      environment[variable.name()] = variable.value();
-    }
-
-    // Launch the subprocess.
-    Option<Try<Subprocess>> external = None();
-
-    if (command.shell()) {
-      // Use the shell variant.
-      if (!command.has_value()) {
-        promise.fail("Shell command is not specified");
-        return;
-      }
-
-      VLOG(2) << "Launching health command '" << command.value() << "'";
-
-      external = process::subprocess(
-          command.value(),
-          Subprocess::PATH("/dev/null"),
-          Subprocess::FD(STDERR_FILENO),
-          Subprocess::FD(STDERR_FILENO),
-          process::NO_SETSID,
-          environment);
-    } else {
-      // Use the exec variant.
-      if (!command.has_value()) {
-        promise.fail("Executable path is not specified");
-        return;
-      }
-
-      vector<string> argv;
-      foreach (const string& arg, command.arguments()) {
-        argv.push_back(arg);
-      }
-
-      VLOG(2) << "Launching health command [" << command.value() << ", "
-              << strings::join(", ", argv) << "]";
-
-      external = process::subprocess(
-          command.value(),
-          argv,
-          Subprocess::PATH("/dev/null"),
-          Subprocess::FD(STDERR_FILENO),
-          Subprocess::FD(STDERR_FILENO),
-          process::NO_SETSID,
-          None(),
-          environment);
-    }
-
-    CHECK_SOME(external);
-
-    if (external.get().isError()) {
-      failure("Error creating subprocess for healthcheck: " +
-              external.get().error());
-      return;
-    }
-
-    pid_t commandPid = external.get().get().pid();
-
-    Future<Option<int>> status = external.get().get().status();
-    status.await(Seconds(check.timeout_seconds()));
-
-    if (!status.isReady()) {
-      string msg = "Command check failed with reason: ";
-      if (status.isFailed()) {
-        msg += "failed with error: " + status.failure();
-      } else if (status.isDiscarded()) {
-        msg += "status future discarded";
-      } else {
-        msg += "status still pending after timeout " +
-               stringify(Seconds(check.timeout_seconds()));
-      }
-
-      if (commandPid != -1) {
-        // Cleanup the external command process.
-        os::killtree(commandPid, SIGKILL);
-        VLOG(1) << "Kill health check command " << commandPid;
-      }
-
-      failure(msg);
-      return;
-    }
-
-    int statusCode = status.get().get();
-    if (statusCode != 0) {
-      string message = "Health command check " + WSTRINGIFY(statusCode);
-      failure(message);
-    } else {
-      success();
-    }
-  }
-
-  void reschedule()
-  {
-    VLOG(1) << "Rescheduling health check in "
-      << Seconds(check.interval_seconds());
-
-    delay(Seconds(check.interval_seconds()), self(), &Self::_healthCheck);
-  }
-
-  Promise<Nothing> promise;
-  HealthCheck check;
-  bool initializing;
-  UPID executor;
-  TaskID taskID;
-  uint32_t consecutiveFailures;
-  process::Time startTime;
-};
-
-} // namespace internal {
-} // namespace mesos {
-
-
 class Flags : public virtual flags::FlagsBase
 {
 public:

http://git-wip-us.apache.org/repos/asf/mesos/blob/1556d9a3/src/launcher/executor.cpp
----------------------------------------------------------------------
diff --git a/src/launcher/executor.cpp b/src/launcher/executor.cpp
index cb23501..6301025 100644
--- a/src/launcher/executor.cpp
+++ b/src/launcher/executor.cpp
@@ -79,6 +79,8 @@
 
 #include "executor/v0_v1executor.hpp"
 
+#include "health-check/health_checker.hpp"
+
 #include "launcher/executor.hpp"
 
 #include "logging/logging.hpp"
@@ -109,6 +111,7 @@ using process::Timer;
 
 using mesos::internal::devolve;
 using mesos::internal::evolve;
+using mesos::internal::HealthChecker;
 using mesos::internal::TaskHealthStatus;
 
 using mesos::internal::protobuf::frameworkHasCapability;
@@ -146,7 +149,6 @@ public:
       killedByHealthCheck(false),
       terminated(false),
       pid(-1),
-      healthPid(-1),
       shutdownGracePeriod(_shutdownGracePeriod),
       frameworkInfo(None()),
       taskId(None()),
@@ -423,7 +425,26 @@ protected:
     cout << "Forked command at " << pid << endl;
 
     if (task->has_health_check()) {
-      launchHealthCheck(task.get());
+      Try<Owned<HealthChecker>> _checker = HealthChecker::create(
+          devolve(task->health_check()),
+          self(),
+          devolve(task->task_id()));
+
+      if (_checker.isError()) {
+        // TODO(gilbert): Consider ABORT and return a TASK_FAILED here.
+        cerr << "Failed to create health checker: "
+             << _checker.error() << endl;
+      } else {
+        checker = _checker.get();
+
+        checker->healthCheck()
+          .onAny([](const Future<Nothing>& future) {
+            // Only possible to be a failure.
+            if (future.isFailed()) {
+              cerr << "Healh check failed" << endl;
+            }
+          });
+      }
     }
 
     // Monitor this process.
@@ -581,17 +602,6 @@ private:
       killGracePeriodStart = Clock::now();
       killed = true;
     }
-
-    // Cleanup health check process.
-    //
-    // TODO(bmahler): Consider doing this after the task has been
-    // reaped, since a framework may be interested in health
-    // information while the task is being killed (consider a
-    // task that takes 30 minutes to be cleanly killed).
-    if (healthPid != -1) {
-      os::killtree(healthPid, SIGKILL);
-      healthPid = -1;
-    }
   }
 
   void reaped(pid_t pid, const Future<Option<int> >& status_)
@@ -677,45 +687,6 @@ private:
     }
   }
 
-  void launchHealthCheck(const TaskInfo& task)
-  {
-    CHECK(task.has_health_check());
-
-    JSON::Object json = JSON::protobuf(task.health_check());
-
-    // Launch the subprocess using 'exec' style so that quotes can
-    // be properly handled.
-    vector<string> argv(4);
-    argv[0] = "mesos-health-check";
-    argv[1] = "--executor=" + stringify(self());
-    argv[2] = "--health_check_json=" + stringify(json);
-    argv[3] = "--task_id=" + task.task_id().value();
-
-    cout << "Launching health check process: "
-         << path::join(healthCheckDir, "mesos-health-check")
-         << " " << argv[1] << " " << argv[2] << " " << argv[3] << endl;
-
-    Try<Subprocess> healthProcess =
-      process::subprocess(
-        path::join(healthCheckDir, "mesos-health-check"),
-        argv,
-        // Intentionally not sending STDIN to avoid health check
-        // commands that expect STDIN input to block.
-        Subprocess::PATH("/dev/null"),
-        Subprocess::FD(STDOUT_FILENO),
-        Subprocess::FD(STDERR_FILENO));
-
-    if (healthProcess.isError()) {
-      cerr << "Unable to launch health process: " << healthProcess.error();
-      return;
-    }
-
-    healthPid = healthProcess.get().pid();
-
-    cout << "Health check process launched at pid: "
-         << stringify(healthPid) << endl;
-  }
-
   void update(
       const TaskID& taskID,
       const TaskState& state,
@@ -775,7 +746,6 @@ private:
 #ifdef __WINDOWS__
   HANDLE processHandle;
 #endif
-  pid_t healthPid;
   Duration shutdownGracePeriod;
   Option<KillPolicy> killPolicy;
   Option<FrameworkInfo> frameworkInfo;
@@ -791,6 +761,7 @@ private:
   Owned<MesosBase> mesos;
   LinkedHashMap<UUID, Call::Update> updates; // Unacknowledged updates.
   Option<TaskInfo> task; // Unacknowledged task.
+  Owned<HealthChecker> checker;
 };
 
 } // namespace internal {