Apache Mesos
executor.hpp
Go to the documentation of this file.
1 // Licensed to the Apache Software Foundation (ASF) under one
2 // or more contributor license agreements. See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership. The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License. You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #ifndef __MESOS_EXECUTOR_HPP__
18 #define __MESOS_EXECUTOR_HPP__
19 
20 #include <map>
21 #include <mutex>
22 #include <string>
23 
24 #include <mesos/mesos.hpp>
25 
26 // Mesos executor interface and executor driver. An executor is
27 // responsible for launching tasks in a framework specific way (i.e.,
28 // creating new threads, new processes, etc). One or more executors
29 // from the same framework may run concurrently on the same machine.
30 // Note that we use the term "executor" fairly loosely to refer to the
31 // code that implements the Executor interface (see below) as well as
32 // the program that is responsible for instantiating a new
33 // MesosExecutorDriver (also below). In fact, while a Mesos slave is
34 // responsible for (forking and) executing the "executor", there is no
35 // reason why whatever the slave executed might itself actually
36 // execute another program which actually instantiates and runs the
37 // MesosSchedulerDriver. The only contract with the slave is that the
38 // program that it invokes does not exit until the "executor" has
39 // completed. Thus, what the slave executes may be nothing more than a
40 // script which actually executes (or forks and waits) the "real"
41 // executor.
42 //
43 // IF YOU FIND YOURSELF MODIFYING COMMENTS HERE PLEASE CONSIDER MAKING
44 // THE SAME MODIFICATIONS FOR OTHER LANGUAGE BINDINGS (e.g., Java:
45 // src/java/src/org/apache/mesos, Python: src/python/src, etc.).
46 
47 // Forward declaration.
48 namespace process {
49 class Latch;
50 } // namespace process {
51 
52 namespace mesos {
53 
54 // A few forward declarations.
55 class ExecutorDriver;
56 
57 namespace internal {
58 class ExecutorProcess;
59 }
60 
61 // Callback interface to be implemented by frameworks' executors. Note
62 // that only one callback will be invoked at a time, so it is not
63 // recommended that you block within a callback because it may cause a
64 // deadlock.
65 //
66 // Each callback includes a pointer to the executor driver that was
67 // used to run this executor. The pointer will not change for the
68 // duration of an executor (i.e., from the point you do
69 // ExecutorDriver::start() to the point that ExecutorDriver::join()
70 // returns). This is intended for convenience so that an executor
71 // doesn't need to store a pointer to the driver itself.
72 //
73 // TODO(bmahler): Consider adding a usage() callback here, that
74 // provides information to the executor about its ResourceUsage.
75 class Executor
76 {
77 public:
78  // Empty virtual destructor (necessary to instantiate subclasses).
79  virtual ~Executor() {}
80 
81  // Invoked once the executor driver has been able to successfully
82  // connect with Mesos. In particular, a scheduler can pass some
83  // data to its executors through the FrameworkInfo.ExecutorInfo's
84  // data field.
85  virtual void registered(
86  ExecutorDriver* driver,
87  const ExecutorInfo& executorInfo,
88  const FrameworkInfo& frameworkInfo,
89  const SlaveInfo& slaveInfo) = 0;
90 
91  // Invoked when the executor reregisters with a restarted slave.
92  virtual void reregistered(
93  ExecutorDriver* driver,
94  const SlaveInfo& slaveInfo) = 0;
95 
96  // Invoked when the executor becomes "disconnected" from the slave
97  // (e.g., the slave is being restarted due to an upgrade).
98  virtual void disconnected(ExecutorDriver* driver) = 0;
99 
100  // Invoked when a task has been launched on this executor (initiated
101  // via Scheduler::launchTasks). Note that this task can be realized
102  // with a thread, a process, or some simple computation, however, no
103  // other callbacks will be invoked on this executor until this
104  // callback has returned.
105  virtual void launchTask(
106  ExecutorDriver* driver,
107  const TaskInfo& task) = 0;
108 
109  // Invoked when a task running within this executor has been killed
110  // (via SchedulerDriver::killTask). Note that no status update will
111  // be sent on behalf of the executor, the executor is responsible
112  // for creating a new TaskStatus (i.e., with TASK_KILLED) and
113  // invoking ExecutorDriver::sendStatusUpdate.
114  virtual void killTask(
115  ExecutorDriver* driver,
116  const TaskID& taskId) = 0;
117 
118  // Invoked when a framework message has arrived for this executor.
119  // These messages are best effort; do not expect a framework message
120  // to be retransmitted in any reliable fashion.
121  virtual void frameworkMessage(
122  ExecutorDriver* driver,
123  const std::string& data) = 0;
124 
125  // Invoked when the executor should terminate all of its currently
126  // running tasks. Note that after a Mesos has determined that an
127  // executor has terminated any tasks that the executor did not send
128  // terminal status updates for (e.g., TASK_KILLED, TASK_FINISHED,
129  // TASK_FAILED, etc) a TASK_LOST status update will be created.
130  virtual void shutdown(ExecutorDriver* driver) = 0;
131 
132  // Invoked when a fatal error has occurred with the executor and/or
133  // executor driver. The driver will be aborted BEFORE invoking this
134  // callback.
135  virtual void error(
136  ExecutorDriver* driver,
137  const std::string& message) = 0;
138 };
139 
140 
141 // Abstract interface for connecting an executor to Mesos. This
142 // interface is used both to manage the executor's lifecycle (start
143 // it, stop it, or wait for it to finish) and to interact with Mesos
144 // (e.g., send status updates, send framework messages, etc.). See
145 // MesosExecutorDriver below for a concrete example of an
146 // ExecutorDriver.
148 {
149 public:
150  // Empty virtual destructor (necessary to instantiate subclasses).
151  virtual ~ExecutorDriver() {}
152 
153  // Starts the executor driver. This needs to be called before any
154  // other driver calls are made.
155  virtual Status start() = 0;
156 
157  // Stops the executor driver.
158  virtual Status stop() = 0;
159 
160  // Aborts the driver so that no more callbacks can be made to the
161  // executor. The semantics of abort and stop have deliberately been
162  // separated so that code can detect an aborted driver (i.e., via
163  // the return status of ExecutorDriver::join, see below), and
164  // instantiate and start another driver if desired (from within the
165  // same process ... although this functionality is currently not
166  // supported for executors).
167  virtual Status abort() = 0;
168 
169  // Waits for the driver to be stopped or aborted, possibly
170  // _blocking_ the current thread indefinitely. The return status of
171  // this function can be used to determine if the driver was aborted
172  // (see mesos.proto for a description of Status).
173  virtual Status join() = 0;
174 
175  // Starts and immediately joins (i.e., blocks on) the driver.
176  virtual Status run() = 0;
177 
178  // Sends a status update to the framework scheduler, retrying as
179  // necessary until an acknowledgement has been received or the
180  // executor is terminated (in which case, a TASK_LOST status update
181  // will be sent). See Scheduler::statusUpdate for more information
182  // about status update acknowledgements.
183  virtual Status sendStatusUpdate(const TaskStatus& status) = 0;
184 
185  // Sends a message to the framework scheduler. These messages are
186  // best effort; do not expect a framework message to be
187  // retransmitted in any reliable fashion.
188  virtual Status sendFrameworkMessage(const std::string& data) = 0;
189 };
190 
191 
192 // Concrete implementation of an ExecutorDriver that connects an
193 // Executor with a Mesos slave. The MesosExecutorDriver is
194 // thread-safe.
195 //
196 // The driver is responsible for invoking the Executor callbacks as it
197 // communicates with the Mesos slave.
198 //
199 // Note that blocking on the MesosExecutorDriver (e.g., via
200 // MesosExecutorDriver::join) doesn't affect the executor callbacks in
201 // anyway because they are handled by a different thread.
202 //
203 // Note that the driver uses GLOG to do its own logging. GLOG flags
204 // can be set via environment variables, prefixing the flag name with
205 // "GLOG_", e.g., "GLOG_v=1". For Mesos specific logging flags see
206 // src/logging/flags.hpp. Mesos flags can also be set via environment
207 // variables, prefixing the flag name with "MESOS_", e.g.,
208 // "MESOS_QUIET=1".
209 //
210 // See src/examples/test_executor.cpp for an example of using the
211 // MesosExecutorDriver.
213 {
214 public:
215  // Creates a new driver that uses the specified Executor. Note, the
216  // executor pointer must outlive the driver.
217  //
218  // Note that the other constructor overload that accepts `environment`
219  // argument is preferable to this one in a multithreaded environment,
220  // because the implementation of this one accesses global environment
221  // which is unsafe due to a potential concurrent modification of the
222  // environment by another thread.
223  explicit MesosExecutorDriver(Executor* executor);
224 
225  // Creates a new driver that uses the specified `Executor` and environment
226  // variables. Note, the executor pointer must outlive the driver.
227  explicit MesosExecutorDriver(
228  Executor* executor,
229  const std::map<std::string, std::string>& environment);
230 
231  // This destructor will block indefinitely if
232  // MesosExecutorDriver::start was invoked successfully (possibly via
233  // MesosExecutorDriver::run) and MesosExecutorDriver::stop has not
234  // been invoked.
235  ~MesosExecutorDriver() override;
236 
237  // See ExecutorDriver for descriptions of these.
238  Status start() override;
239  Status stop() override;
240  Status abort() override;
241  Status join() override;
242  Status run() override;
243  Status sendStatusUpdate(const TaskStatus& status) override;
244  Status sendFrameworkMessage(const std::string& data) override;
245 
246 private:
247  friend class internal::ExecutorProcess;
248 
249  Executor* executor;
250 
251  // Libprocess process for communicating with slave.
252  internal::ExecutorProcess* process;
253 
254  // Mutex for enforcing serial execution of all non-callbacks.
255  std::recursive_mutex mutex;
256 
257  // Latch for waiting until driver terminates.
258  process::Latch* latch;
259 
260  // Current status of the driver.
261  Status status;
262 
263  std::map<std::string, std::string> environment;
264 };
265 
266 } // namespace mesos {
267 
268 #endif // __MESOS_EXECUTOR_HPP__
Definition: executor.hpp:147
Result< ProcessStatus > status(pid_t pid)
Definition: proc.hpp:166
Definition: executor.hpp:212
std::string join(const std::string &path1, const std::string &path2, const char _separator=os::PATH_SEPARATOR)
Definition: path.hpp:116
virtual ~Executor()
Definition: executor.hpp:79
Try< Nothing > start(const std::string &name)
Starts the slice with the given name (via &#39;systemctl start <name>&#39;).
virtual ~ExecutorDriver()
Definition: executor.hpp:151
Environment * environment
Definition: agent.hpp:25
Definition: executor.hpp:75
Future< R > run(R(*method)())
Definition: run.hpp:55
Result< Process > process(pid_t pid)
Definition: freebsd.hpp:30
Definition: attributes.hpp:24
std::string error(const std::string &msg, uint32_t code)
Definition: executor.hpp:48
Definition: latch.hpp:24