{"action":"created","comment":{"url":"https://api.github.com/repos/apache/spark/pulls/comments/39635426","id":39635426,"diff_hunk":"@@ -0,0 +1,981 @@\n+/*\n+ * Licensed to the Apache Software Foundation (ASF) under one or more\n+ * contributor license agreements.  See the NOTICE file distributed with\n+ * this work for additional information regarding copyright ownership.\n+ * The ASF licenses this file to You under the Apache License, Version 2.0\n+ * (the \"License\"); you may not use this file except in compliance with\n+ * the License.  You may obtain a copy of the License at\n+ *\n+ *    http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+package org.apache.spark.deploy.history.yarn\n+\n+import java.net.{ConnectException, URI}\n+import java.util.concurrent.LinkedBlockingQueue\n+import java.util.concurrent.atomic.{AtomicBoolean, AtomicInteger}\n+\n+import scala.collection.mutable.LinkedList\n+import scala.util.control.NonFatal\n+\n+import org.apache.hadoop.conf.Configuration\n+import org.apache.hadoop.security.UserGroupInformation\n+import org.apache.hadoop.service.{AbstractService, Service}\n+import org.apache.hadoop.yarn.api.records.{ApplicationAttemptId, ApplicationId}\n+import org.apache.hadoop.yarn.api.records.timeline.{TimelineDomain, TimelineEntity, TimelinePutResponse}\n+import org.apache.hadoop.yarn.client.api.TimelineClient\n+import org.apache.hadoop.yarn.conf.YarnConfiguration\n+\n+import org.apache.spark.deploy.history.yarn.YarnTimelineUtils._\n+import org.apache.spark.scheduler._\n+import org.apache.spark.scheduler.cluster.YarnExtensionService\n+import org.apache.spark.util.{SystemClock, Clock, Utils}\n+import org.apache.spark.{Logging, SparkContext}\n+\n+/**\n+ * Implements a Hadoop service with the init/start logic replaced by that\n+ * of the YarnService.\n+ * <p>\n+ * As [[AbstractService]] implements `close()`, routing\n+ * to its `stop` method, calling `close()` is sufficient\n+ * to stop the service instance.\n+ * <p>\n+ * However, when registered to receive spark events, the service will continue to\n+ * receive them until the spark context is stopped. Events received when this service\n+ * is in a `STOPPED` state will be discarded.\n+ */\n+private[spark] class YarnHistoryService  extends AbstractService(\"History Service\")\n+  with YarnExtensionService with Logging {\n+\n+  import org.apache.spark.deploy.history.yarn.YarnHistoryService._\n+  /**\n+   * Spark context; valid once started\n+   */\n+  private var sparkContext: SparkContext = _\n+\n+  /** application ID. */\n+  private var _applicationId: ApplicationId = _\n+\n+  /** attempt ID this will be null if the service is started in yarn-client mode */\n+  private var _attemptId: Option[ApplicationAttemptId] = None\n+\n+  /** YARN timeline client */\n+  private var timelineClient: Option[TimelineClient] = None\n+\n+  /** registered event listener */\n+  private var listener: Option[YarnEventListener] = None\n+\n+  /** Applicaton name */\n+  private var appName: String = _\n+\n+  /** Application ID from the spark start event */\n+  private var sparkApplicationId: Option[String] = None\n+\n+  /** Optional Attempt ID from the spark start event */\n+  private var sparkApplicationAttemptId: Option[String] = None\n+\n+  /** user name as derived from `SPARK_USER` env var or `UGI` */\n+  private var userName: String = Utils.getCurrentUserName\n+\n+  /**\n+   * Clock for recording time\n+   */\n+  private val clock: Clock = new SystemClock()\n+\n+  /**\n+   * Start time of the application, as received in the start event.\n+   */\n+  private var startTime: Long = _\n+\n+  /** number of events to batch up before posting*/\n+  private var batchSize: Int = DEFAULT_BATCH_SIZE\n+\n+  /** queue of actions*/\n+  private val actionQueue = new LinkedBlockingQueue[QueuedAction]\n+\n+  /** cache layer to handle timeline client failure.*/\n+  private var entityList = new LinkedList[TimelineEntity]\n+\n+  /** current entity; wil be created on demand. */\n+  private var curEntity: Option[TimelineEntity] = None\n+\n+  /** Has a start event been processed? */\n+  private val appStartEventProcessed = new AtomicBoolean(false)\n+\n+  /* has the application event event been processed */\n+  private val appEndEventProcessed = new AtomicBoolean(false)\n+\n+  /** How many events have been received in the current entity */\n+  private var currentEventCount = 0\n+\n+  /** counter of events processed -that is have been through handleEvent()*/\n+  private val eventsProcessed: AtomicInteger = new AtomicInteger(0)\n+\n+  /** counter of events queued. */\n+  private val eventsQueued: AtomicInteger = new AtomicInteger(0)\n+\n+  /** how many event postings failed? */\n+  private val eventPostFailures: AtomicInteger = new AtomicInteger(0)\n+\n+  /** how many flushes have taken place? */\n+  private val flushCount = new AtomicInteger(0)\n+\n+  /** Event handler */\n+  private var eventHandlingThread: Option[Thread] = None\n+\n+  /**\n+   * Flag to indicate the thread is stopped; events aren't being\n+   * processed.\n+   */\n+  private val stopped: AtomicBoolean = new AtomicBoolean(true)\n+\n+  /**\n+   * boolean to track whether a thread is active or not, for tests to\n+   * monitor and see if the thread has completed.\n+   */\n+  private val postThreadActive: AtomicBoolean = new AtomicBoolean(false)\n+\n+  /**\n+   * object used for a lock on entity operations\n+   */\n+  private val entityLock: AnyRef = new AnyRef\n+\n+  /**\n+   * How long to wait for shutdown before giving up\n+   */\n+  private var maxTimeToWaitOnShutdown: Long = SHUTDOWN_WAIT_TIME\n+\n+  /** Domain ID for entities: may be null */\n+  private var domainId: String = null\n+\n+  /** URI to timeline web application -valid after `serviceStart()` */\n+  private var timelineWebappAddress: URI = _\n+\n+  /**\n+   * Create a timeline client and start it. This does not update the\n+   * `timelineClient` field, though it does verify that the field\n+   * is unset.\n+   *\n+   * The method is private to the package so that tests can access it, which\n+   * some of the mock tests do to override the timeline client creation.\n+   * @return the timeline client\n+   */\n+  private [yarn] def createTimelineClient(): TimelineClient = {\n+    require(timelineClient.isEmpty, \"timeline client already set\")\n+    YarnTimelineUtils.createTimelineClient(sparkContext)\n+  }\n+\n+  /**\n+   * Get the timeline client.\n+   * @return the client\n+   * @throws Exception if the timeline client is not currently running\n+   */\n+  def getTimelineClient: TimelineClient = {\n+    timelineClient.getOrElse(throw new Exception(\"Timeline client not running\"))\n+  }\n+\n+  /**\n+   * Get the total number of processed events\n+   * @return counter of events processed\n+   */\n+  def getEventsProcessed: Int = {\n+    eventsProcessed.get\n+  }\n+\n+  /**\n+   * Get the total number of events queued\n+   * @return the total event count\n+   */\n+  def getEventsQueued: Int = {\n+    eventsQueued.get\n+  }\n+\n+  /**\n+   * Get the current size of the queue\n+   * @return the current queue length\n+   */\n+  def getQueueSize: Int = {\n+    actionQueue.size\n+  }\n+\n+  /**\n+   * Get the current batch size\n+   * @return the batch size\n+   */\n+  def getBatchSize: Int = {\n+    batchSize\n+  }\n+\n+  /**\n+   * Get the total number of failed posts events\n+   * @return counter of timeline post operations which failed\n+   */\n+  def getEventPostFailures: Int = {\n+    eventPostFailures.get\n+  }\n+\n+  /**\n+   * is the asynchronous posting thread active?\n+   * @return true if the post thread has started; false if it has not yet/ever started, or\n+   *         if it has finished.\n+   */\n+  def isPostThreadActive: Boolean = {\n+    postThreadActive.get\n+  }\n+\n+  /**\n+   * The YARN application ID of this history service\n+   * @return the application ID provided when the service started\n+   */\n+  def applicationId: ApplicationId = { _applicationId }\n+\n+  /**\n+   * The YARN attempt ID of this history service\n+   * @return the attempt ID provided when the service started\n+   */\n+  def attemptId: Option[ApplicationAttemptId] = { _attemptId }\n+\n+  /**\n+   * Reset the timeline client\n+   * <p>\n+   * 1. Stop the timeline client service if running.\n+   * 2. set the `timelineClient` field to `None`\n+   */\n+  def stopTimelineClient(): Unit = {\n+    stopOptionalService(timelineClient)\n+    timelineClient = None\n+  }\n+\n+  /**\n+   * Create the timeline domain","path":"yarn/history/src/main/scala/org/apache/spark/deploy/history/yarn/YarnHistoryService.scala","position":256,"original_position":256,"commit_id":"34c0283f09ffc9261f07e32eedb6ae00ca1ef6ae","original_commit_id":"34c0283f09ffc9261f07e32eedb6ae00ca1ef6ae","user":{"login":"steveloughran","id":162090,"avatar_url":"https://avatars.githubusercontent.com/u/162090?v=3","gravatar_id":"","url":"https://api.github.com/users/steveloughran","html_url":"https://github.com/steveloughran","followers_url":"https://api.github.com/users/steveloughran/followers","following_url":"https://api.github.com/users/steveloughran/following{/other_user}","gists_url":"https://api.github.com/users/steveloughran/gists{/gist_id}","starred_url":"https://api.github.com/users/steveloughran/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/steveloughran/subscriptions","organizations_url":"https://api.github.com/users/steveloughran/orgs","repos_url":"https://api.github.com/users/steveloughran/repos","events_url":"https://api.github.com/users/steveloughran/events{/privacy}","received_events_url":"https://api.github.com/users/steveloughran/received_events","type":"User","site_admin":false},"body":"OK","created_at":"2015-09-16T14:23:15Z","updated_at":"2015-09-16T14:23:15Z","html_url":"https://github.com/apache/spark/pull/8744#discussion_r39635426","pull_request_url":"https://api.github.com/repos/apache/spark/pulls/8744","_links":{"self":{"href":"https://api.github.com/repos/apache/spark/pulls/comments/39635426"},"html":{"href":"https://github.com/apache/spark/pull/8744#discussion_r39635426"},"pull_request":{"href":"https://api.github.com/repos/apache/spark/pulls/8744"}}},"pull_request":{"url":"https://api.github.com/repos/apache/spark/pulls/8744","id":44922174,"html_url":"https://github.com/apache/spark/pull/8744","diff_url":"https://github.com/apache/spark/pull/8744.diff","patch_url":"https://github.com/apache/spark/pull/8744.patch","issue_url":"https://api.github.com/repos/apache/spark/issues/8744","number":8744,"state":"open","locked":false,"title":"SPARK-1537 publisher-side code and tests","user":{"login":"steveloughran","id":162090,"avatar_url":"https://avatars.githubusercontent.com/u/162090?v=3","gravatar_id":"","url":"https://api.github.com/users/steveloughran","html_url":"https://github.com/steveloughran","followers_url":"https://api.github.com/users/steveloughran/followers","following_url":"https://api.github.com/users/steveloughran/following{/other_user}","gists_url":"https://api.github.com/users/steveloughran/gists{/gist_id}","starred_url":"https://api.github.com/users/steveloughran/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/steveloughran/subscriptions","organizations_url":"https://api.github.com/users/steveloughran/orgs","repos_url":"https://api.github.com/users/steveloughran/repos","events_url":"https://api.github.com/users/steveloughran/events{/privacy}","received_events_url":"https://api.github.com/users/steveloughran/received_events","type":"User","site_admin":false},"body":"This is the publisher side of the SPARK-1537 Yarn timeline server integration: the event listener to asynchronously publish events to ATS; the basic unit and mock tests to verify functionality.","created_at":"2015-09-14T12:07:58Z","updated_at":"2015-09-16T14:23:15Z","closed_at":null,"merged_at":null,"merge_commit_sha":"598b248e2ed5db913a4c11db548ef28a34592858","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/apache/spark/pulls/8744/commits","review_comments_url":"https://api.github.com/repos/apache/spark/pulls/8744/comments","review_comment_url":"https://api.github.com/repos/apache/spark/pulls/comments{/number}","comments_url":"https://api.github.com/repos/apache/spark/issues/8744/comments","statuses_url":"https://api.github.com/repos/apache/spark/statuses/34c0283f09ffc9261f07e32eedb6ae00ca1ef6ae","head":{"label":"steveloughran:stevel/feature/SPARK-1537-publisher","ref":"stevel/feature/SPARK-1537-publisher","sha":"34c0283f09ffc9261f07e32eedb6ae00ca1ef6ae","user":{"login":"steveloughran","id":162090,"avatar_url":"https://avatars.githubusercontent.com/u/162090?v=3","gravatar_id":"","url":"https://api.github.com/users/steveloughran","html_url":"https://github.com/steveloughran","followers_url":"https://api.github.com/users/steveloughran/followers","following_url":"https://api.github.com/users/steveloughran/following{/other_user}","gists_url":"https://api.github.com/users/steveloughran/gists{/gist_id}","starred_url":"https://api.github.com/users/steveloughran/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/steveloughran/subscriptions","organizations_url":"https://api.github.com/users/steveloughran/orgs","repos_url":"https://api.github.com/users/steveloughran/repos","events_url":"https://api.github.com/users/steveloughran/events{/privacy}","received_events_url":"https://api.github.com/users/steveloughran/received_events","type":"User","site_admin":false},"repo":{"id":32387210,"name":"spark","full_name":"steveloughran/spark","owner":{"login":"steveloughran","id":162090,"avatar_url":"https://avatars.githubusercontent.com/u/162090?v=3","gravatar_id":"","url":"https://api.github.com/users/steveloughran","html_url":"https://github.com/steveloughran","followers_url":"https://api.github.com/users/steveloughran/followers","following_url":"https://api.github.com/users/steveloughran/following{/other_user}","gists_url":"https://api.github.com/users/steveloughran/gists{/gist_id}","starred_url":"https://api.github.com/users/steveloughran/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/steveloughran/subscriptions","organizations_url":"https://api.github.com/users/steveloughran/orgs","repos_url":"https://api.github.com/users/steveloughran/repos","events_url":"https://api.github.com/users/steveloughran/events{/privacy}","received_events_url":"https://api.github.com/users/steveloughran/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/steveloughran/spark","description":"Mirror of Apache Spark","fork":true,"url":"https://api.github.com/repos/steveloughran/spark","forks_url":"https://api.github.com/repos/steveloughran/spark/forks","keys_url":"https://api.github.com/repos/steveloughran/spark/keys{/key_id}","collaborators_url":"https://api.github.com/repos/steveloughran/spark/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/steveloughran/spark/teams","hooks_url":"https://api.github.com/repos/steveloughran/spark/hooks","issue_events_url":"https://api.github.com/repos/steveloughran/spark/issues/events{/number}","events_url":"https://api.github.com/repos/steveloughran/spark/events","assignees_url":"https://api.github.com/repos/steveloughran/spark/assignees{/user}","branches_url":"https://api.github.com/repos/steveloughran/spark/branches{/branch}","tags_url":"https://api.github.com/repos/steveloughran/spark/tags","blobs_url":"https://api.github.com/repos/steveloughran/spark/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/steveloughran/spark/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/steveloughran/spark/git/refs{/sha}","trees_url":"https://api.github.com/repos/steveloughran/spark/git/trees{/sha}","statuses_url":"https://api.github.com/repos/steveloughran/spark/statuses/{sha}","languages_url":"https://api.github.com/repos/steveloughran/spark/languages","stargazers_url":"https://api.github.com/repos/steveloughran/spark/stargazers","contributors_url":"https://api.github.com/repos/steveloughran/spark/contributors","subscribers_url":"https://api.github.com/repos/steveloughran/spark/subscribers","subscription_url":"https://api.github.com/repos/steveloughran/spark/subscription","commits_url":"https://api.github.com/repos/steveloughran/spark/commits{/sha}","git_commits_url":"https://api.github.com/repos/steveloughran/spark/git/commits{/sha}","comments_url":"https://api.github.com/repos/steveloughran/spark/comments{/number}","issue_comment_url":"https://api.github.com/repos/steveloughran/spark/issues/comments{/number}","contents_url":"https://api.github.com/repos/steveloughran/spark/contents/{+path}","compare_url":"https://api.github.com/repos/steveloughran/spark/compare/{base}...{head}","merges_url":"https://api.github.com/repos/steveloughran/spark/merges","archive_url":"https://api.github.com/repos/steveloughran/spark/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/steveloughran/spark/downloads","issues_url":"https://api.github.com/repos/steveloughran/spark/issues{/number}","pulls_url":"https://api.github.com/repos/steveloughran/spark/pulls{/number}","milestones_url":"https://api.github.com/repos/steveloughran/spark/milestones{/number}","notifications_url":"https://api.github.com/repos/steveloughran/spark/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/steveloughran/spark/labels{/name}","releases_url":"https://api.github.com/repos/steveloughran/spark/releases{/id}","created_at":"2015-03-17T10:36:33Z","updated_at":"2015-03-17T10:36:52Z","pushed_at":"2015-09-16T12:30:13Z","git_url":"git://github.com/steveloughran/spark.git","ssh_url":"git@github.com:steveloughran/spark.git","clone_url":"https://github.com/steveloughran/spark.git","svn_url":"https://github.com/steveloughran/spark","homepage":null,"size":122305,"stargazers_count":0,"watchers_count":0,"language":"Scala","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"apache:master","ref":"master","sha":"d81565465cc6d4f38b4ed78036cded630c700388","user":{"login":"apache","id":47359,"avatar_url":"https://avatars.githubusercontent.com/u/47359?v=3","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"repo":{"id":17165658,"name":"spark","full_name":"apache/spark","owner":{"login":"apache","id":47359,"avatar_url":"https://avatars.githubusercontent.com/u/47359?v=3","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/apache/spark","description":"Mirror of Apache Spark","fork":false,"url":"https://api.github.com/repos/apache/spark","forks_url":"https://api.github.com/repos/apache/spark/forks","keys_url":"https://api.github.com/repos/apache/spark/keys{/key_id}","collaborators_url":"https://api.github.com/repos/apache/spark/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/apache/spark/teams","hooks_url":"https://api.github.com/repos/apache/spark/hooks","issue_events_url":"https://api.github.com/repos/apache/spark/issues/events{/number}","events_url":"https://api.github.com/repos/apache/spark/events","assignees_url":"https://api.github.com/repos/apache/spark/assignees{/user}","branches_url":"https://api.github.com/repos/apache/spark/branches{/branch}","tags_url":"https://api.github.com/repos/apache/spark/tags","blobs_url":"https://api.github.com/repos/apache/spark/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/apache/spark/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/apache/spark/git/refs{/sha}","trees_url":"https://api.github.com/repos/apache/spark/git/trees{/sha}","statuses_url":"https://api.github.com/repos/apache/spark/statuses/{sha}","languages_url":"https://api.github.com/repos/apache/spark/languages","stargazers_url":"https://api.github.com/repos/apache/spark/stargazers","contributors_url":"https://api.github.com/repos/apache/spark/contributors","subscribers_url":"https://api.github.com/repos/apache/spark/subscribers","subscription_url":"https://api.github.com/repos/apache/spark/subscription","commits_url":"https://api.github.com/repos/apache/spark/commits{/sha}","git_commits_url":"https://api.github.com/repos/apache/spark/git/commits{/sha}","comments_url":"https://api.github.com/repos/apache/spark/comments{/number}","issue_comment_url":"https://api.github.com/repos/apache/spark/issues/comments{/number}","contents_url":"https://api.github.com/repos/apache/spark/contents/{+path}","compare_url":"https://api.github.com/repos/apache/spark/compare/{base}...{head}","merges_url":"https://api.github.com/repos/apache/spark/merges","archive_url":"https://api.github.com/repos/apache/spark/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/apache/spark/downloads","issues_url":"https://api.github.com/repos/apache/spark/issues{/number}","pulls_url":"https://api.github.com/repos/apache/spark/pulls{/number}","milestones_url":"https://api.github.com/repos/apache/spark/milestones{/number}","notifications_url":"https://api.github.com/repos/apache/spark/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/apache/spark/labels{/name}","releases_url":"https://api.github.com/repos/apache/spark/releases{/id}","created_at":"2014-02-25T08:00:08Z","updated_at":"2015-09-16T13:40:57Z","pushed_at":"2015-09-16T14:08:15Z","git_url":"git://github.com/apache/spark.git","ssh_url":"git@github.com:apache/spark.git","clone_url":"https://github.com/apache/spark.git","svn_url":"https://github.com/apache/spark","homepage":null,"size":1620499,"stargazers_count":5445,"watchers_count":5445,"language":"Scala","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":5022,"mirror_url":"git://git.apache.org/spark.git","open_issues_count":338,"forks":5022,"open_issues":338,"watchers":5445,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/apache/spark/pulls/8744"},"html":{"href":"https://github.com/apache/spark/pull/8744"},"issue":{"href":"https://api.github.com/repos/apache/spark/issues/8744"},"comments":{"href":"https://api.github.com/repos/apache/spark/issues/8744/comments"},"review_comments":{"href":"https://api.github.com/repos/apache/spark/pulls/8744/comments"},"review_comment":{"href":"https://api.github.com/repos/apache/spark/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/apache/spark/pulls/8744/commits"},"statuses":{"href":"https://api.github.com/repos/apache/spark/statuses/34c0283f09ffc9261f07e32eedb6ae00ca1ef6ae"}}}}