
tasks.queue.ProxyTask.scala Maven / Gradle / Ivy
/*
* The MIT License
*
* Copyright (c) 2015 ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE, Switzerland,
* Group Fellay
* Modified work, Copyright (c) 2016 Istvan Bartha
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package tasks.queue
import akka.actor.{Actor, PoisonPill, ActorRef}
import tasks.fileservice._
import tasks.shared._
import tasks._
import tasks.wire._
import scala.concurrent.Promise
import cats.effect.IO
import tasks.caching.TaskResultCache
/* Local proxy of the remotely executed task */
class ProxyTask[Input, Output](
taskId: TaskId,
inputDeserializer: Spore[Unit, Deserializer[Input]],
outputSerializer: Spore[Unit, Serializer[Output]],
function: Spore[Input, ComputationEnvironment => IO[Output]],
input: Input,
writer: Serializer[Input],
reader: Deserializer[Output],
resourceConsumed: VersionedResourceRequest,
queueActor: ActorRef,
fileServicePrefix: FileServicePrefix,
cache: TaskResultCache,
priority: Priority,
promise: Promise[Output],
labels: Labels,
lineage: TaskLineage,
noCache: Boolean
) extends Actor
with akka.actor.ActorLogging {
private def distributeResult(result: Output): Unit = {
log.debug("Completing promise.")
promise.success(result)
}
private def notifyListenersOnFailure(cause: Throwable): Unit =
promise.failure(cause)
private def startTask(cache: Boolean): Unit = {
val persisted: Option[Input] = input match {
case x: HasPersistent[_] => Some(x.persistent.asInstanceOf[Input])
case _ => None
}
val hash: HashedTaskDescription =
HashedTaskDescription(
taskId,
writer.hash(persisted.getOrElse(input))
)
val scheduleTask = ScheduleTask(
description = hash,
inputDeserializer = inputDeserializer.as[AnyRef, AnyRef],
outputSerializer = outputSerializer.as[AnyRef, AnyRef],
function = function.as[AnyRef, AnyRef],
resource = resourceConsumed,
queueActor = queueActor,
fileServicePrefix = fileServicePrefix,
tryCache = cache,
priority = priority,
labels = labels,
lineage = lineage,
proxy = self
)
log.debug("proxy submitting ScheduleTask object to queue.")
queueActor ! scheduleTask
}
override def preStart() = {
log.debug("ProxyTask prestart.")
startTask(cache = true)
}
override def postStop() = {
log.debug("ProxyTask stopped. {} {} {}", taskId, input, self)
}
def receive = {
case NeedInput =>
sender() ! InputData(Base64DataHelpers(writer(input)), noCache)
case MessageFromTask(untypedOutput, retrievedFromCache) =>
reader(Base64DataHelpers.toBytes(untypedOutput.data)) match {
case Right(output) =>
log.debug(
"MessageFromTask received from: {}, {}, {}",
sender(),
untypedOutput,
output
)
distributeResult(output)
self ! PoisonPill
case Left(error) if retrievedFromCache =>
log.error(
s"MessageFromTask received from cache and failed to decode: ${sender()}, $untypedOutput, $error. Task is rescheduled without caching."
)
startTask(cache = false)
case Left(error) =>
log.error(
error,
s"MessageFromTask received not from cache and failed to decode: ${sender()}, $untypedOutput, $error. Execution failed."
)
notifyListenersOnFailure(new RuntimeException(error))
self ! PoisonPill
}
case TaskFailedMessageToProxy(_, cause) =>
log.error(cause, "Execution failed. ")
notifyListenersOnFailure(cause)
self ! PoisonPill
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy