{"action":"created","comment":{"url":"https://api.github.com/repos/broadinstitute/cromwell/pulls/comments/31663391","id":31663391,"diff_hunk":"@@ -2,88 +2,87 @@ package cromwell.engine\n \n import akka.actor.{Actor, ActorRef, Props}\n import akka.event.{Logging, LoggingReceive}\n-import cromwell.binding.Call\n+import akka.pattern.ask\n+import akka.util.Timeout\n import cromwell.binding.values.WdlValue\n-import cromwell.engine.CallActor._\n-import cromwell.engine.WorkflowActor.InvalidOperation\n+import cromwell.binding.{Call, WorkflowOutputs}\n import cromwell.engine.backend.Backend\n import cromwell.util.TryUtil\n \n+import scala.concurrent.ExecutionContext.Implicits.global\n+import scala.concurrent.Future\n+import scala.concurrent.duration._\n import scala.language.postfixOps\n-import scala.util.Success\n \n \n object CallActor {\n \n   sealed trait CallActorMessage\n-\n-  case class Start(call: Call, backend: Backend, symbolStore: SymbolStore) extends CallActorMessage\n-  // Does this message need to pass along the SymbolStore for output expression evaluation?\n-  case class Run(commandLine: String, backend: Backend, call: Call, symbolStore: SymbolStore) extends CallActorMessage\n+  case object Start extends CallActorMessage\n   case class Started(call: Call) extends CallActorMessage\n-  case class Done(call: Call, outputs: Map[String, WdlValue]) extends CallActorMessage\n+  case class Completed(call: Call, outputs: WorkflowOutputs) extends CallActorMessage\n   case class Failed(call: Call, failure: String) extends CallActorMessage\n \n-  def props: Props = Props(classOf[CallActor])\n+  def props(call: Call, backend: Backend, storeActor: ActorRef, name: String): Props =\n+    Props(new CallActor(call, backend, storeActor))\n+\n+  implicit val ActorTimeout = Timeout(5 seconds)\n }\n \n-/**\n- * Probably not the right level of abstraction for a system that supports richer\n- * control structures like loops, conditionals, scatter etc., but this should be\n- * sufficient for Sprint 2/3.\n- */\n-class CallActor extends Actor {\n+\n+/** Actor to manage the execution of a single call. */\n+class CallActor(call: Call, backend: Backend, storeActor: ActorRef) extends Actor {\n+  import CallActor.ActorTimeout\n \n   private val log = Logging(context.system, this)\n \n-  private var _creator: Option[ActorRef] = None\n-\n-  private def isStarted: Boolean = _creator.isDefined\n-\n-  private def creator: ActorRef = _creator.get\n-\n-  private def notStarted: Receive = {\n-    LoggingReceive {\n-      case Start(call, backend, symbolStore) =>\n-        val inputs = symbolStore.locallyQualifiedInputs(call)\n-        val tryCommandLine = call.task.command.instantiate(inputs)\n-        tryCommandLine match {\n-          case Success(commandLine) =>\n-            _creator = Option(sender())\n-            self ! Run(commandLine, backend, call, symbolStore)\n-            creator ! Started(call)\n-            context.become(started)\n-          case failure =>\n-            sender ! failure\n-        }\n-\n-      case bad@_ if !isStarted =>\n-        sender ! InvalidOperation(s\"Received message $bad, but not yet Started.\")\n-    }\n+  override def receive = LoggingReceive {\n+    case CallActor.Start => handleStart()\n+    case badMessage =>\n+      val diagnostic = s\"Received unexpected message $badMessage.\"\n+      log.error(diagnostic)\n+      context.parent ! CallActor.Failed(call, diagnostic)\n   }\n \n-  private def started: Receive = {\n-    LoggingReceive {\n-      case Run(commandLine, backend, call, symbolStore) =>\n-        log.info(self + \" executing command: \" + commandLine)\n-        val tryOutputs = backend.executeCommand(commandLine, call, call.task.outputs, symbolStore)\n-        val (successes, failures) = tryOutputs.partition { _._2.isSuccess }\n-\n-        if (failures.isEmpty) {\n-          // Materialize the Successes.\n-          val outputs = successes.map { case (key, value) => key -> value.get }\n-          creator ! Done(call, outputs)\n-        } else {\n-          val errorMessages = TryUtil.stringifyFailures(failures.values).mkString(\"\\n\")\n-\n-          log.error(errorMessages)\n-          creator ! Failed(call, errorMessages)\n-        }\n-\n-      case unknown @_ =>\n-        sender ! InvalidOperation(s\"Unexpected message $unknown.\")\n+  /**\n+   * Performs the following steps:\n+   * <ol>\n+   *   <li>Collects the locally qualified inputs from the store actor.</li>\n+   *   <li>Instantiates the command line using these inputs.</li>\n+   *   <li>If the above completes successfully, messages the sender with `Started`,\n+   *   otherwise messages `Failed`.</li>\n+   *   <li>Executes the command with these inputs.</li>\n+   *   <li>Collects outputs in a `Map[String, Try[WdlValue]]`.</li>\n+   *   <li>If there are no `Failure`s among the outputs, messages the parent actor\n+   *   with `Completed`, otherwise messages `Failed`.</li>\n+\n+   * </ol>\n+   */\n+  private def handleStart(): Unit = {\n+    // Record the original sender here and not in the yield over the `Future`, as the\n+    // value of sender() when that code executes may be different than what it is here.\n+    val originalSender = sender()\n+\n+    for {\n+      inputs <- (storeActor ? StoreActor.GetLocallyQualifiedInputs(call)).mapTo[Map[String, WdlValue]]\n+      commandLine <- Future.fromTry(call.task.command.instantiate(inputs))\n+    } yield {\n+      originalSender ! CallActor.Started(call)\n+      val tryOutputs = backend.executeCommand(commandLine, call, call.task.outputs, s => inputs.get(s).get)\n+      val (successes, failures) = tryOutputs.partition {","path":"src/main/scala/cromwell/engine/CallActor.scala","position":131,"original_position":131,"commit_id":"54bd5775d12452cefd65773b868ab5c2ad8687eb","original_commit_id":"272aa6dedc6c3587bff2b9c278423d3d2af34866","user":{"login":"geoffjentry","id":961771,"avatar_url":"https://avatars.githubusercontent.com/u/961771?v=3","gravatar_id":"","url":"https://api.github.com/users/geoffjentry","html_url":"https://github.com/geoffjentry","followers_url":"https://api.github.com/users/geoffjentry/followers","following_url":"https://api.github.com/users/geoffjentry/following{/other_user}","gists_url":"https://api.github.com/users/geoffjentry/gists{/gist_id}","starred_url":"https://api.github.com/users/geoffjentry/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/geoffjentry/subscriptions","organizations_url":"https://api.github.com/users/geoffjentry/orgs","repos_url":"https://api.github.com/users/geoffjentry/repos","events_url":"https://api.github.com/users/geoffjentry/events{/privacy}","received_events_url":"https://api.github.com/users/geoffjentry/received_events","type":"User","site_admin":false},"body":":+1:","created_at":"2015-06-03T19:59:06Z","updated_at":"2015-06-03T19:59:06Z","html_url":"https://github.com/broadinstitute/cromwell/pull/32#discussion_r31663391","pull_request_url":"https://api.github.com/repos/broadinstitute/cromwell/pulls/32","_links":{"self":{"href":"https://api.github.com/repos/broadinstitute/cromwell/pulls/comments/31663391"},"html":{"href":"https://github.com/broadinstitute/cromwell/pull/32#discussion_r31663391"},"pull_request":{"href":"https://api.github.com/repos/broadinstitute/cromwell/pulls/32"}}},"pull_request":{"url":"https://api.github.com/repos/broadinstitute/cromwell/pulls/32","id":36677184,"html_url":"https://github.com/broadinstitute/cromwell/pull/32","diff_url":"https://github.com/broadinstitute/cromwell/pull/32.diff","patch_url":"https://github.com/broadinstitute/cromwell/pull/32.patch","issue_url":"https://api.github.com/repos/broadinstitute/cromwell/issues/32","number":32,"state":"closed","locked":false,"title":"Move workflow-level store updates behind an actor.","user":{"login":"mcovarr","id":10790523,"avatar_url":"https://avatars.githubusercontent.com/u/10790523?v=3","gravatar_id":"","url":"https://api.github.com/users/mcovarr","html_url":"https://github.com/mcovarr","followers_url":"https://api.github.com/users/mcovarr/followers","following_url":"https://api.github.com/users/mcovarr/following{/other_user}","gists_url":"https://api.github.com/users/mcovarr/gists{/gist_id}","starred_url":"https://api.github.com/users/mcovarr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mcovarr/subscriptions","organizations_url":"https://api.github.com/users/mcovarr/orgs","repos_url":"https://api.github.com/users/mcovarr/repos","events_url":"https://api.github.com/users/mcovarr/events{/privacy}","received_events_url":"https://api.github.com/users/mcovarr/received_events","type":"User","site_admin":false},"body":"Work for DSDEEPB-380.","created_at":"2015-06-01T22:19:35Z","updated_at":"2015-06-03T19:59:06Z","closed_at":"2015-06-03T19:46:38Z","merged_at":"2015-06-03T19:46:38Z","merge_commit_sha":"bc0d8508b97a171cdfeeb28f64a6410fb2c9f745","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/broadinstitute/cromwell/pulls/32/commits","review_comments_url":"https://api.github.com/repos/broadinstitute/cromwell/pulls/32/comments","review_comment_url":"https://api.github.com/repos/broadinstitute/cromwell/pulls/comments{/number}","comments_url":"https://api.github.com/repos/broadinstitute/cromwell/issues/32/comments","statuses_url":"https://api.github.com/repos/broadinstitute/cromwell/statuses/54bd5775d12452cefd65773b868ab5c2ad8687eb","head":{"label":"broadinstitute:mlc_store_actor","ref":"mlc_store_actor","sha":"54bd5775d12452cefd65773b868ab5c2ad8687eb","user":{"login":"broadinstitute","id":393552,"avatar_url":"https://avatars.githubusercontent.com/u/393552?v=3","gravatar_id":"","url":"https://api.github.com/users/broadinstitute","html_url":"https://github.com/broadinstitute","followers_url":"https://api.github.com/users/broadinstitute/followers","following_url":"https://api.github.com/users/broadinstitute/following{/other_user}","gists_url":"https://api.github.com/users/broadinstitute/gists{/gist_id}","starred_url":"https://api.github.com/users/broadinstitute/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/broadinstitute/subscriptions","organizations_url":"https://api.github.com/users/broadinstitute/orgs","repos_url":"https://api.github.com/users/broadinstitute/repos","events_url":"https://api.github.com/users/broadinstitute/events{/privacy}","received_events_url":"https://api.github.com/users/broadinstitute/received_events","type":"Organization","site_admin":false},"repo":{"id":34136406,"name":"cromwell","full_name":"broadinstitute/cromwell","owner":{"login":"broadinstitute","id":393552,"avatar_url":"https://avatars.githubusercontent.com/u/393552?v=3","gravatar_id":"","url":"https://api.github.com/users/broadinstitute","html_url":"https://github.com/broadinstitute","followers_url":"https://api.github.com/users/broadinstitute/followers","following_url":"https://api.github.com/users/broadinstitute/following{/other_user}","gists_url":"https://api.github.com/users/broadinstitute/gists{/gist_id}","starred_url":"https://api.github.com/users/broadinstitute/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/broadinstitute/subscriptions","organizations_url":"https://api.github.com/users/broadinstitute/orgs","repos_url":"https://api.github.com/users/broadinstitute/repos","events_url":"https://api.github.com/users/broadinstitute/events{/privacy}","received_events_url":"https://api.github.com/users/broadinstitute/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/broadinstitute/cromwell","description":"Workflow Execution Engine using WDL","fork":false,"url":"https://api.github.com/repos/broadinstitute/cromwell","forks_url":"https://api.github.com/repos/broadinstitute/cromwell/forks","keys_url":"https://api.github.com/repos/broadinstitute/cromwell/keys{/key_id}","collaborators_url":"https://api.github.com/repos/broadinstitute/cromwell/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/broadinstitute/cromwell/teams","hooks_url":"https://api.github.com/repos/broadinstitute/cromwell/hooks","issue_events_url":"https://api.github.com/repos/broadinstitute/cromwell/issues/events{/number}","events_url":"https://api.github.com/repos/broadinstitute/cromwell/events","assignees_url":"https://api.github.com/repos/broadinstitute/cromwell/assignees{/user}","branches_url":"https://api.github.com/repos/broadinstitute/cromwell/branches{/branch}","tags_url":"https://api.github.com/repos/broadinstitute/cromwell/tags","blobs_url":"https://api.github.com/repos/broadinstitute/cromwell/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/broadinstitute/cromwell/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/broadinstitute/cromwell/git/refs{/sha}","trees_url":"https://api.github.com/repos/broadinstitute/cromwell/git/trees{/sha}","statuses_url":"https://api.github.com/repos/broadinstitute/cromwell/statuses/{sha}","languages_url":"https://api.github.com/repos/broadinstitute/cromwell/languages","stargazers_url":"https://api.github.com/repos/broadinstitute/cromwell/stargazers","contributors_url":"https://api.github.com/repos/broadinstitute/cromwell/contributors","subscribers_url":"https://api.github.com/repos/broadinstitute/cromwell/subscribers","subscription_url":"https://api.github.com/repos/broadinstitute/cromwell/subscription","commits_url":"https://api.github.com/repos/broadinstitute/cromwell/commits{/sha}","git_commits_url":"https://api.github.com/repos/broadinstitute/cromwell/git/commits{/sha}","comments_url":"https://api.github.com/repos/broadinstitute/cromwell/comments{/number}","issue_comment_url":"https://api.github.com/repos/broadinstitute/cromwell/issues/comments{/number}","contents_url":"https://api.github.com/repos/broadinstitute/cromwell/contents/{+path}","compare_url":"https://api.github.com/repos/broadinstitute/cromwell/compare/{base}...{head}","merges_url":"https://api.github.com/repos/broadinstitute/cromwell/merges","archive_url":"https://api.github.com/repos/broadinstitute/cromwell/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/broadinstitute/cromwell/downloads","issues_url":"https://api.github.com/repos/broadinstitute/cromwell/issues{/number}","pulls_url":"https://api.github.com/repos/broadinstitute/cromwell/pulls{/number}","milestones_url":"https://api.github.com/repos/broadinstitute/cromwell/milestones{/number}","notifications_url":"https://api.github.com/repos/broadinstitute/cromwell/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/broadinstitute/cromwell/labels{/name}","releases_url":"https://api.github.com/repos/broadinstitute/cromwell/releases{/id}","created_at":"2015-04-17T19:39:36Z","updated_at":"2015-05-17T12:45:42Z","pushed_at":"2015-06-03T19:46:39Z","git_url":"git://github.com/broadinstitute/cromwell.git","ssh_url":"git@github.com:broadinstitute/cromwell.git","clone_url":"https://github.com/broadinstitute/cromwell.git","svn_url":"https://github.com/broadinstitute/cromwell","homepage":"http://broadinstitute.github.io/cromwell/","size":2751,"stargazers_count":1,"watchers_count":1,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":1,"default_branch":"master"}},"base":{"label":"broadinstitute:develop","ref":"develop","sha":"6c1e3414249283af71a3beaf2066bc56f12b51b5","user":{"login":"broadinstitute","id":393552,"avatar_url":"https://avatars.githubusercontent.com/u/393552?v=3","gravatar_id":"","url":"https://api.github.com/users/broadinstitute","html_url":"https://github.com/broadinstitute","followers_url":"https://api.github.com/users/broadinstitute/followers","following_url":"https://api.github.com/users/broadinstitute/following{/other_user}","gists_url":"https://api.github.com/users/broadinstitute/gists{/gist_id}","starred_url":"https://api.github.com/users/broadinstitute/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/broadinstitute/subscriptions","organizations_url":"https://api.github.com/users/broadinstitute/orgs","repos_url":"https://api.github.com/users/broadinstitute/repos","events_url":"https://api.github.com/users/broadinstitute/events{/privacy}","received_events_url":"https://api.github.com/users/broadinstitute/received_events","type":"Organization","site_admin":false},"repo":{"id":34136406,"name":"cromwell","full_name":"broadinstitute/cromwell","owner":{"login":"broadinstitute","id":393552,"avatar_url":"https://avatars.githubusercontent.com/u/393552?v=3","gravatar_id":"","url":"https://api.github.com/users/broadinstitute","html_url":"https://github.com/broadinstitute","followers_url":"https://api.github.com/users/broadinstitute/followers","following_url":"https://api.github.com/users/broadinstitute/following{/other_user}","gists_url":"https://api.github.com/users/broadinstitute/gists{/gist_id}","starred_url":"https://api.github.com/users/broadinstitute/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/broadinstitute/subscriptions","organizations_url":"https://api.github.com/users/broadinstitute/orgs","repos_url":"https://api.github.com/users/broadinstitute/repos","events_url":"https://api.github.com/users/broadinstitute/events{/privacy}","received_events_url":"https://api.github.com/users/broadinstitute/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/broadinstitute/cromwell","description":"Workflow Execution Engine using WDL","fork":false,"url":"https://api.github.com/repos/broadinstitute/cromwell","forks_url":"https://api.github.com/repos/broadinstitute/cromwell/forks","keys_url":"https://api.github.com/repos/broadinstitute/cromwell/keys{/key_id}","collaborators_url":"https://api.github.com/repos/broadinstitute/cromwell/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/broadinstitute/cromwell/teams","hooks_url":"https://api.github.com/repos/broadinstitute/cromwell/hooks","issue_events_url":"https://api.github.com/repos/broadinstitute/cromwell/issues/events{/number}","events_url":"https://api.github.com/repos/broadinstitute/cromwell/events","assignees_url":"https://api.github.com/repos/broadinstitute/cromwell/assignees{/user}","branches_url":"https://api.github.com/repos/broadinstitute/cromwell/branches{/branch}","tags_url":"https://api.github.com/repos/broadinstitute/cromwell/tags","blobs_url":"https://api.github.com/repos/broadinstitute/cromwell/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/broadinstitute/cromwell/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/broadinstitute/cromwell/git/refs{/sha}","trees_url":"https://api.github.com/repos/broadinstitute/cromwell/git/trees{/sha}","statuses_url":"https://api.github.com/repos/broadinstitute/cromwell/statuses/{sha}","languages_url":"https://api.github.com/repos/broadinstitute/cromwell/languages","stargazers_url":"https://api.github.com/repos/broadinstitute/cromwell/stargazers","contributors_url":"https://api.github.com/repos/broadinstitute/cromwell/contributors","subscribers_url":"https://api.github.com/repos/broadinstitute/cromwell/subscribers","subscription_url":"https://api.github.com/repos/broadinstitute/cromwell/subscription","commits_url":"https://api.github.com/repos/broadinstitute/cromwell/commits{/sha}","git_commits_url":"https://api.github.com/repos/broadinstitute/cromwell/git/commits{/sha}","comments_url":"https://api.github.com/repos/broadinstitute/cromwell/comments{/number}","issue_comment_url":"https://api.github.com/repos/broadinstitute/cromwell/issues/comments{/number}","contents_url":"https://api.github.com/repos/broadinstitute/cromwell/contents/{+path}","compare_url":"https://api.github.com/repos/broadinstitute/cromwell/compare/{base}...{head}","merges_url":"https://api.github.com/repos/broadinstitute/cromwell/merges","archive_url":"https://api.github.com/repos/broadinstitute/cromwell/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/broadinstitute/cromwell/downloads","issues_url":"https://api.github.com/repos/broadinstitute/cromwell/issues{/number}","pulls_url":"https://api.github.com/repos/broadinstitute/cromwell/pulls{/number}","milestones_url":"https://api.github.com/repos/broadinstitute/cromwell/milestones{/number}","notifications_url":"https://api.github.com/repos/broadinstitute/cromwell/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/broadinstitute/cromwell/labels{/name}","releases_url":"https://api.github.com/repos/broadinstitute/cromwell/releases{/id}","created_at":"2015-04-17T19:39:36Z","updated_at":"2015-05-17T12:45:42Z","pushed_at":"2015-06-03T19:46:39Z","git_url":"git://github.com/broadinstitute/cromwell.git","ssh_url":"git@github.com:broadinstitute/cromwell.git","clone_url":"https://github.com/broadinstitute/cromwell.git","svn_url":"https://github.com/broadinstitute/cromwell","homepage":"http://broadinstitute.github.io/cromwell/","size":2751,"stargazers_count":1,"watchers_count":1,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":1,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/broadinstitute/cromwell/pulls/32"},"html":{"href":"https://github.com/broadinstitute/cromwell/pull/32"},"issue":{"href":"https://api.github.com/repos/broadinstitute/cromwell/issues/32"},"comments":{"href":"https://api.github.com/repos/broadinstitute/cromwell/issues/32/comments"},"review_comments":{"href":"https://api.github.com/repos/broadinstitute/cromwell/pulls/32/comments"},"review_comment":{"href":"https://api.github.com/repos/broadinstitute/cromwell/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/broadinstitute/cromwell/pulls/32/commits"},"statuses":{"href":"https://api.github.com/repos/broadinstitute/cromwell/statuses/54bd5775d12452cefd65773b868ab5c2ad8687eb"}}}}