blob: 07a468defe8c586398ff889661fc3959cd0916ca [file] [log] [blame]
/**
* 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 __MESOS_EXECUTOR_HPP__
#define __MESOS_EXECUTOR_HPP__
#include <pthread.h>
#include <string>
#include <mesos/mesos.hpp>
/**
* Mesos executor interface and executor driver. An executor is
* responsible for launching tasks in a framework specific way (i.e.,
* creating new threads, new processes, etc). One or more executors
* from the same framework may run concurrently on the same
* machine. Note that we use the term "executor" fairly loosely to
* refer to the code that implements the Executor interface (see
* below) as well as the program that is responsible for instantiating
* a new MesosExecutorDriver (also below). In fact, while a Mesos
* slave is responsible for (forking and) executing the "executor",
* there is no reason why whatever the slave executed might itself
* actually execute another program which actually instantiates and
* runs the MesosSchedulerDriver. The only contract with the slave is
* that the program that it invokes does not exit until the "executor"
* has completed. Thus, what the slave executes may be nothing more
* than a script which actually executes (or forks and waits) the
* "real" executor.
*
* IF YOU FIND YOURSELF MODIFYING COMMENTS HERE PLEASE CONSIDER MAKING
* THE SAME MODIFICATIONS FOR OTHER LANGUAGE BINDINGS (e.g., Java:
* src/java/src/org/apache/mesos, Python: src/python/src, etc.).
*/
namespace mesos {
// A few forward declarations.
class ExecutorDriver;
namespace internal {
class ExecutorProcess;
}
/**
* Callback interface to be implemented by frameworks' executors. Note
* that only one callback will be invoked at a time, so it is not
* recommended that you block within a callback because it may cause a
* deadlock.
*
* Each callback includes a pointer to the executor driver that was
* used to run this executor. The pointer will not change for the
* duration of an executor (i.e., from the point you do
* ExecutorDriver::start() to the point that ExecutorDriver::join()
* returns). This is intended for convenience so that an executor
* doesn't need to store a pointer to the driver itself.
*/
// TODO(bmahler): Consider adding a usage() callback here, that provides
// information to the executor about it's ResourceUsage.
class Executor
{
public:
/**
* Empty virtual destructor (necessary to instantiate subclasses).
*/
virtual ~Executor() {}
/**
* Invoked once the executor driver has been able to successfully
* connect with Mesos. In particular, a scheduler can pass some
* data to its executors through the FrameworkInfo.ExecutorInfo's
* data field.
*/
virtual void registered(ExecutorDriver* driver,
const ExecutorInfo& executorInfo,
const FrameworkInfo& frameworkInfo,
const SlaveInfo& slaveInfo) = 0;
/**
* Invoked when the executor re-registers with a restarted slave.
*/
virtual void reregistered(ExecutorDriver* driver,
const SlaveInfo& slaveInfo) = 0;
/**
* Invoked when the executor becomes "disconnected" from the slave
* (e.g., the slave is being restarted due to an upgrade).
*/
virtual void disconnected(ExecutorDriver* driver) = 0;
/**
* Invoked when a task has been launched on this executor (initiated
* via Scheduler::launchTasks). Note that this task can be realized
* with a thread, a process, or some simple computation, however, no
* other callbacks will be invoked on this executor until this
* callback has returned.
*/
virtual void launchTask(ExecutorDriver* driver,
const TaskInfo& task) = 0;
/**
* Invoked when a task running within this executor has been killed
* (via SchedulerDriver::killTask). Note that no status update will
* be sent on behalf of the executor, the executor is responsible
* for creating a new TaskStatus (i.e., with TASK_KILLED) and
* invoking ExecutorDriver::sendStatusUpdate.
*/
virtual void killTask(ExecutorDriver* driver, const TaskID& taskId) = 0;
/**
* Invoked when a framework message has arrived for this
* executor. These messages are best effort; do not expect a
* framework message to be retransmitted in any reliable fashion.
*/
virtual void frameworkMessage(ExecutorDriver* driver,
const std::string& data) = 0;
/**
* Invoked when the executor should terminate all of its currently
* running tasks. Note that after a Mesos has determined that an
* executor has terminated any tasks that the executor did not send
* terminal status updates for (e.g., TASK_KILLED, TASK_FINISHED,
* TASK_FAILED, etc) a TASK_LOST status update will be created.
*/
virtual void shutdown(ExecutorDriver* driver) = 0;
/**
* Invoked when a fatal error has occured with the executor and/or
* executor driver. The driver will be aborted BEFORE invoking this
* callback.
*/
virtual void error(ExecutorDriver* driver, const std::string& message) = 0;
};
/**
* Abstract interface for connecting an executor to Mesos. This
* interface is used both to manage the executor's lifecycle (start
* it, stop it, or wait for it to finish) and to interact with Mesos
* (e.g., send status updates, send framework messages, etc.). See
* MesosExecutorDriver below for a concrete example of an
* ExecutorDriver.
*/
class ExecutorDriver
{
public:
/**
* Empty virtual destructor (necessary to instantiate subclasses).
*/
virtual ~ExecutorDriver() {}
/**
* Starts the executor driver. This needs to be called before any
* other driver calls are made.
*/
virtual Status start() = 0;
/**
* Stops the executor driver.
*/
virtual Status stop() = 0;
/**
* Aborts the driver so that no more callbacks can be made to the
* executor. The semantics of abort and stop have deliberately been
* separated so that code can detect an aborted driver (i.e., via
* the return status of ExecutorDriver::join, see below), and
* instantiate and start another driver if desired (from within the
* same process ... although this functionality is currently not
* supported for executors).
*/
virtual Status abort() = 0;
/**
* Waits for the driver to be stopped or aborted, possibly
* _blocking_ the current thread indefinitely. The return status of
* this function can be used to determine if the driver was aborted
* (see mesos.proto for a description of Status).
*/
virtual Status join() = 0;
/**
* Starts and immediately joins (i.e., blocks on) the driver.
*/
virtual Status run() = 0;
/**
* Sends a status update to the framework scheduler, retrying as
* necessary until an acknowledgement has been received or the
* executor is terminated (in which case, a TASK_LOST status update
* will be sent). See Scheduler::statusUpdate for more information
* about status update acknowledgements.
*/
virtual Status sendStatusUpdate(const TaskStatus& status) = 0;
/**
* Sends a message to the framework scheduler. These messages are
* best effort; do not expect a framework message to be
* retransmitted in any reliable fashion.
*/
virtual Status sendFrameworkMessage(const std::string& data) = 0;
};
/**
* Concrete implementation of an ExecutorDriver that connects an
* Executor with a Mesos slave. The MesosExecutorDriver is thread-safe.
*
* The driver is responsible for invoking the Executor callbacks as it
* communicates with the Mesos slave.
*
* Note that blocking on the MesosExecutorDriver (e.g., via
* MesosExecutorDriver::join) doesn't affect the executor callbacks in
* anyway because they are handled by a different thread.
*
* Note that the driver uses GLOG to do its own logging. GLOG flags can
* be set via environment variables, prefixing the flag name with
* "GLOG_", e.g., "GLOG_v=1". For Mesos specific logging flags see
* src/logging/flags.hpp. Mesos flags can also be set via environment
* variables, prefixing the flag name with "MESOS_", e.g.,
* "MESOS_QUIET=1".
*
* See src/examples/test_executor.cpp for an example of using the
* MesosExecutorDriver.
*/
class MesosExecutorDriver : public ExecutorDriver
{
public:
/**
* Creates a new driver that uses the specified Executor. Note, the
* executor pointer must outlive the driver.
*/
explicit MesosExecutorDriver(Executor* executor);
/**
* This destructor will block indefinitely if
* MesosExecutorDriver::start was invoked successfully (possibly via
* MesosExecutorDriver::run) and MesosExecutorDriver::stop has not
* been invoked.
*/
virtual ~MesosExecutorDriver();
/**
* See ExecutorDriver for descriptions of these.
*/
virtual Status start();
virtual Status stop();
virtual Status abort();
virtual Status join();
virtual Status run();
virtual Status sendStatusUpdate(const TaskStatus& status);
virtual Status sendFrameworkMessage(const std::string& data);
private:
friend class internal::ExecutorProcess;
Executor* executor;
// Libprocess process for communicating with slave.
internal::ExecutorProcess* process;
// Mutex to enforce all non-callbacks are execute serially.
pthread_mutex_t mutex;
// Condition variable for waiting until driver terminates.
pthread_cond_t cond;
// Current status of the driver.
Status status;
};
} // namespace mesos {
#endif // __MESOS_EXECUTOR_HPP__