-
Notifications
You must be signed in to change notification settings - Fork 841
687 expose recent scheduling decisions #1130
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -107,11 +107,22 @@ class MarathonScheduler @Inject() ( | |
log.debug("Received offer %s".format(offer)) | ||
|
||
val matchingTask = taskQueue.pollMatching { app => | ||
newTask(app, offer).map(app -> _) | ||
val result: TaskBuilder.BuildResult = newTask(app, offer) | ||
result match { | ||
case declined: TaskBuilder.BuildDeclined => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need for curly braces here. |
||
eventBus.publish(TaskOfferDeclinedEvent(app.id, declined.reason.getBytes)) | ||
None | ||
} | ||
case success: TaskBuilder.BuildSuccess => Some((app, success)) | ||
} | ||
} | ||
|
||
matchingTask.foreach { | ||
case (app, (taskInfo, ports)) => | ||
matchingTask match { | ||
case None => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need for curly braces here. |
||
log.debug("Offer doesn't match request. Declining.") | ||
driver.declineOffer(offer.getId) | ||
} | ||
case Some((app, TaskBuilder.BuildSuccess(taskInfo, ports))) => | ||
val marathonTask = MarathonTasks.makeTask( | ||
taskInfo.getTaskId.getValue, offer.getHostname, ports, | ||
offer.getAttributesList.asScala, app.version) | ||
|
@@ -124,11 +135,6 @@ class MarathonScheduler @Inject() ( | |
// here it is assumed that the health checks for the current | ||
// version are already running. | ||
} | ||
|
||
if (matchingTask.isEmpty) { | ||
log.debug("Offer doesn't match request. Declining.") | ||
driver.declineOffer(offer.getId) | ||
} | ||
} | ||
catch { | ||
case t: Throwable => | ||
|
@@ -276,7 +282,7 @@ class MarathonScheduler @Inject() ( | |
|
||
private def newTask( | ||
app: AppDefinition, | ||
offer: Offer): Option[(TaskInfo, Seq[Long])] = { | ||
offer: Offer): TaskBuilder.BuildResult = { | ||
new TaskBuilder(app, taskIdUtil.newTaskId, taskTracker, config, mapper).buildIfMatches(offer) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ import java.util.concurrent.Semaphore | |
import akka.actor._ | ||
import akka.event.EventStream | ||
import com.fasterxml.jackson.databind.ObjectMapper | ||
import mesosphere.mesos.TaskBuilder.BuildResult | ||
import org.apache.mesos.Protos.{ TaskState, TaskID, TaskStatus, TaskInfo } | ||
import org.apache.mesos.SchedulerDriver | ||
import org.slf4j.LoggerFactory | ||
|
@@ -40,6 +41,7 @@ class MarathonSchedulerActor( | |
storage: StorageProvider, | ||
eventBus: EventStream, | ||
taskFailureRepository: TaskFailureRepository, | ||
taskOffersDeclinedRepository: TaskOffersDeclinedRepository, | ||
config: MarathonConf) extends Actor with ActorLogging with Stash { | ||
import context.dispatcher | ||
|
||
|
@@ -79,7 +81,7 @@ class MarathonSchedulerActor( | |
) | ||
|
||
historyActor = context.actorOf( | ||
Props(classOf[HistoryActor], eventBus, taskFailureRepository), "HistoryActor") | ||
Props(classOf[HistoryActor], eventBus, taskFailureRepository, taskOffersDeclinedRepository), "HistoryActor") | ||
} | ||
|
||
def receive: Receive = suspended | ||
|
@@ -447,7 +449,7 @@ class SchedulerActions( | |
} healthCheckManager.reconcileWith(app.id) | ||
|
||
private def newTask(app: AppDefinition, | ||
offer: Offer): Option[(TaskInfo, Seq[Long])] = { | ||
offer: Offer): BuildResult = { | ||
// TODO this should return a MarathonTask | ||
val builder = new TaskBuilder( | ||
app, | ||
|
@@ -457,10 +459,10 @@ class SchedulerActions( | |
mapper | ||
) | ||
|
||
builder.buildIfMatches(offer) map { | ||
case (task, ports) => | ||
val taskBuilder = task.toBuilder | ||
taskBuilder.build -> ports | ||
builder.buildIfMatches(offer) match { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like this pattern match doesn't do anything. In both cases, the result (or the equivalent) of the call to |
||
case TaskBuilder.BuildSuccess(task, ports) => | ||
TaskBuilder.BuildSuccess(task.toBuilder.build, ports) | ||
case declined: TaskBuilder.BuildDeclined => declined | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,14 +2,17 @@ package mesosphere.marathon.event | |
|
||
import akka.actor.{ Actor, ActorLogging } | ||
import akka.event.EventStream | ||
import mesosphere.marathon.state.{ TaskFailure, TaskFailureRepository } | ||
import mesosphere.marathon.state.{ TaskOffersDeclinedRepository, TaskFailure, TaskFailureRepository } | ||
|
||
class HistoryActor(eventBus: EventStream, taskFailureRepository: TaskFailureRepository) | ||
class HistoryActor(eventBus: EventStream, | ||
taskFailureRepository: TaskFailureRepository, | ||
taskOfferDeclinedRepository: TaskOffersDeclinedRepository) | ||
extends Actor with ActorLogging { | ||
|
||
override def preStart(): Unit = { | ||
eventBus.subscribe(self, classOf[MesosStatusUpdateEvent]) | ||
eventBus.subscribe(self, classOf[AppTerminatedEvent]) | ||
eventBus.subscribe(self, classOf[TaskOfferDeclinedEvent]) | ||
} | ||
|
||
def receive: Receive = { | ||
|
@@ -20,6 +23,8 @@ class HistoryActor(eventBus: EventStream, taskFailureRepository: TaskFailureRepo | |
|
||
case AppTerminatedEvent(appId, eventType, timestamp) => | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Upon receipt of an |
||
taskFailureRepository.expunge(appId) | ||
|
||
case e: TaskOfferDeclinedEvent => taskOfferDeclinedRepository.store(e.appId, e) | ||
} | ||
|
||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package mesosphere.marathon.state | ||
|
||
import mesosphere.marathon.event.TaskOfferDeclinedEvent | ||
|
||
import scala.collection.mutable | ||
|
||
class TaskOffersDeclinedRepository() { | ||
|
||
protected[this] val tasksDeclined = mutable.Map[PathId, TaskOfferDeclinedEvent]() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please use |
||
|
||
def store(id: PathId, value: TaskOfferDeclinedEvent): Unit = | ||
synchronized { tasksDeclined(id) = value } | ||
|
||
def expunge(id: PathId): Unit = | ||
synchronized { tasksDeclined -= id } | ||
|
||
def current(id: PathId): Option[TaskOfferDeclinedEvent] = tasksDeclined.get(id) | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,7 +31,7 @@ class TaskBuilder(app: AppDefinition, | |
|
||
val log = Logger.getLogger(getClass.getName) | ||
|
||
def buildIfMatches(offer: Offer): Option[(TaskInfo, Seq[Long])] = { | ||
def buildIfMatches(offer: Offer): TaskBuilder.BuildResult = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💯 |
||
var cpuRole = "" | ||
var memRole = "" | ||
var diskRole = "" | ||
|
@@ -44,11 +44,10 @@ class TaskBuilder(app: AppDefinition, | |
diskRole = disk | ||
portsResource = ranges | ||
case _ => | ||
log.info( | ||
s"No matching offer for ${app.id} (need cpus=${app.cpus}, mem=${app.mem}, " + | ||
s"disk=${app.disk}, ports=${app.hostPorts}) : " + offer | ||
) | ||
return None | ||
val reason = s"No matching offer for ${app.id} (need cpus=${app.cpus}, mem=${app.mem}, " + | ||
s"disk=${app.disk}, ports=${app.hostPorts}) : " + offer | ||
log.info(reason) | ||
return TaskBuilder.BuildDeclined(reason) | ||
} | ||
|
||
val executor: Executor = if (app.executor == "") { | ||
|
@@ -143,7 +142,7 @@ class TaskBuilder(app: AppDefinition, | |
|
||
mesosHealthChecks.headOption.foreach(builder.setHealthCheck) | ||
|
||
Some(builder.build -> ports) | ||
TaskBuilder.BuildSuccess(builder.build, ports) | ||
} | ||
|
||
private def offerMatches(offer: Offer): Option[(String, String, String, RangesResource)] = { | ||
|
@@ -203,6 +202,10 @@ class TaskBuilder(app: AppDefinition, | |
|
||
object TaskBuilder { | ||
|
||
sealed trait BuildResult | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about adding |
||
case class BuildDeclined(reason: String) extends BuildResult | ||
case class BuildSuccess(info: TaskInfo, ports: Seq[Long]) extends BuildResult | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please make both case classes |
||
|
||
def commandInfo(app: AppDefinition, taskId: Option[TaskID], host: Option[String], ports: Seq[Long]): CommandInfo = { | ||
val containerPorts = for (pms <- app.portMappings) yield pms.map(_.containerPort) | ||
val declaredPorts = containerPorts.getOrElse(app.ports) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ import akka.actor.{ ActorSystem, Props } | |
import akka.testkit.{ TestProbe, TestActorRef, TestKit } | ||
import mesosphere.marathon.Protos.MarathonTask | ||
import mesosphere.marathon.event.{ HistoryActor, AppTerminatedEvent, MesosStatusUpdateEvent } | ||
import mesosphere.marathon.state.{ TaskFailure, TaskFailureRepository, AppDefinition, PathId } | ||
import mesosphere.marathon.state._ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please revert this change. Wildcard imports are to be avoided, especially for only four items. |
||
import mesosphere.marathon.tasks.TaskTracker | ||
import mesosphere.marathon.upgrade.StoppingBehavior.SynchronizeTasks | ||
import mesosphere.marathon.{ MarathonSpec, SchedulerActions, TaskUpgradeCanceledException } | ||
|
@@ -27,12 +27,14 @@ class AppStopActorTest | |
var scheduler: SchedulerActions = _ | ||
var taskTracker: TaskTracker = _ | ||
var taskFailureRepository: TaskFailureRepository = _ | ||
var declinedRepository: TaskOffersDeclinedRepository = _ | ||
|
||
before { | ||
driver = mock[SchedulerDriver] | ||
scheduler = mock[SchedulerActions] | ||
taskTracker = mock[TaskTracker] | ||
taskFailureRepository = mock[TaskFailureRepository] | ||
declinedRepository = mock[TaskOffersDeclinedRepository] | ||
} | ||
|
||
test("Stop App") { | ||
|
@@ -59,7 +61,8 @@ class AppStopActorTest | |
Props( | ||
new HistoryActor( | ||
system.eventStream, | ||
taskFailureRepository | ||
taskFailureRepository, | ||
declinedRepository | ||
) | ||
) | ||
) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These parameters are unused, please remove them.