{"action":"created","comment":{"url":"https://api.github.com/repos/akka/akka/pulls/comments/124798851","pull_request_review_id":47116285,"id":124798851,"diff_hunk":"@@ -160,58 +161,78 @@ private[cluster] final case class Gossip(\n   }\n \n   /**\n-   * Checks if we have a cluster convergence. If there are any unreachable nodes then we can't have a convergence -\n-   * waiting for user to act (issuing DOWN) or leader to act (issuing DOWN through auto-down).\n+   * Checks if we have a cluster convergence. If there are any in team node pairs that cannot reach each other\n+   * then we can't have a convergence until those nodes reach each other again or one of them is downed\n    *\n    * @return true if convergence have been reached and false if not\n    */\n-  def convergence(selfUniqueAddress: UniqueAddress, exitingConfirmed: Set[UniqueAddress]): Boolean = {\n-    // First check that:\n-    //   1. we don't have any members that are unreachable, excluding observations from members\n-    //      that have status DOWN, or\n-    //   2. all unreachable members in the set have status DOWN or EXITING\n-    // Else we can't continue to check for convergence\n-    // When that is done we check that all members with a convergence\n-    // status is in the seen table, i.e. has seen this version\n-    val unreachable = reachabilityExcludingDownedObservers.allUnreachableOrTerminated.collect {\n-      case node if (node != selfUniqueAddress && !exitingConfirmed(node)) ⇒ member(node)\n+  def convergence(team: Team, selfUniqueAddress: UniqueAddress, exitingConfirmed: Set[UniqueAddress]): Boolean = {\n+    // Find cluster members in the team that are unreachable from other members of the team\n+    // excluding observations from members outside of the team, that have status DOWN or is passed in as confirmed exiting.\n+    val unreachableInTeam = teamReachabilityExcludingDownedObservers(team).allUnreachableOrTerminated.collect {\n+      case node if node != selfUniqueAddress && !exitingConfirmed(node) ⇒ member(node)\n     }\n-    unreachable.forall(m ⇒ Gossip.convergenceSkipUnreachableWithMemberStatus(m.status)) &&\n-      !members.exists(m ⇒ Gossip.convergenceMemberStatus(m.status) &&\n-        !(seenByNode(m.uniqueAddress) || exitingConfirmed(m.uniqueAddress)))\n+\n+    // If another member in the team that is UP or LEAVING and has not seen this gossip or is exiting\n+    // convergence cannot be reached\n+    def teamMemberHinderingConvergenceExists =\n+      members.exists(member ⇒\n+        member.team == team &&\n+          Gossip.convergenceMemberStatus(member.status) &&\n+          !(seenByNode(member.uniqueAddress) || exitingConfirmed(member.uniqueAddress))\n+      )\n+\n+    // unreachables outside of the team or with status DOWN or EXITING does not affect convergence\n+    def allUnreachablesCanBeIgnored =\n+      unreachableInTeam.forall(unreachable ⇒ Gossip.convergenceSkipUnreachableWithMemberStatus(unreachable.status))\n+\n+    allUnreachablesCanBeIgnored && !teamMemberHinderingConvergenceExists\n   }\n \n   lazy val reachabilityExcludingDownedObservers: Reachability = {\n     val downed = members.collect { case m if m.status == Down ⇒ m }\n     overview.reachability.removeObservers(downed.map(_.uniqueAddress))\n   }\n \n-  def isLeader(node: UniqueAddress, selfUniqueAddress: UniqueAddress): Boolean =\n-    leader(selfUniqueAddress).contains(node)\n+  /**\n+   * @return reachability for team nodes, with observations from outside the team or from downed nodes filtered out\n+   */\n+  def teamReachabilityExcludingDownedObservers(team: Team): Reachability = {\n+    val membersToExclude = members.collect { case m if m.status == Down || m.team != team ⇒ m.uniqueAddress }\n+    overview.reachability.removeObservers(membersToExclude).remove(members.collect { case m if m.team != team ⇒ m.uniqueAddress })\n+  }\n+\n+  def isTeamLeader(team: Team, node: UniqueAddress, selfUniqueAddress: UniqueAddress): Boolean =\n+    teamLeader(team, selfUniqueAddress).contains(node)\n \n-  def leader(selfUniqueAddress: UniqueAddress): Option[UniqueAddress] =\n-    leaderOf(members, selfUniqueAddress)\n+  def teamLeader(team: Team, selfUniqueAddress: UniqueAddress): Option[UniqueAddress] =\n+    leaderOf(team, members, selfUniqueAddress)\n \n-  def roleLeader(role: String, selfUniqueAddress: UniqueAddress): Option[UniqueAddress] =\n-    leaderOf(members.filter(_.hasRole(role)), selfUniqueAddress)\n+  def roleLeader(team: Team, role: String, selfUniqueAddress: UniqueAddress): Option[UniqueAddress] =\n+    leaderOf(team, members.filter(_.hasRole(role)), selfUniqueAddress)\n \n-  def leaderOf(mbrs: immutable.SortedSet[Member], selfUniqueAddress: UniqueAddress): Option[UniqueAddress] = {\n+  def leaderOf(team: Team, mbrs: immutable.SortedSet[Member], selfUniqueAddress: UniqueAddress): Option[UniqueAddress] = {\n     val reachableMembers =\n-      if (overview.reachability.isAllReachable) mbrs.filterNot(_.status == Down)\n-      else mbrs.filter(m ⇒ m.status != Down &&\n-        (overview.reachability.isReachable(m.uniqueAddress) || m.uniqueAddress == selfUniqueAddress))\n+      if (overview.reachability.isAllReachable) mbrs.filter(m ⇒ m.team == team && m.status != Down)\n+      else mbrs.filter(m ⇒\n+        m.team == team &&\n+          m.status != Down &&\n+          (overview.reachability.isReachable(m.uniqueAddress) || m.uniqueAddress == selfUniqueAddress))","path":"akka-cluster/src/main/scala/akka/cluster/Gossip.scala","position":93,"original_position":93,"commit_id":"d47a701d6074aac3371c9233e5f6310224669165","original_commit_id":"d47a701d6074aac3371c9233e5f6310224669165","user":{"login":"patriknw","id":336161,"avatar_url":"https://avatars0.githubusercontent.com/u/336161?v=3","gravatar_id":"","url":"https://api.github.com/users/patriknw","html_url":"https://github.com/patriknw","followers_url":"https://api.github.com/users/patriknw/followers","following_url":"https://api.github.com/users/patriknw/following{/other_user}","gists_url":"https://api.github.com/users/patriknw/gists{/gist_id}","starred_url":"https://api.github.com/users/patriknw/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/patriknw/subscriptions","organizations_url":"https://api.github.com/users/patriknw/orgs","repos_url":"https://api.github.com/users/patriknw/repos","events_url":"https://api.github.com/users/patriknw/events{/privacy}","received_events_url":"https://api.github.com/users/patriknw/received_events","type":"User","site_admin":false},"body":"search for other usages also","created_at":"2017-06-29T13:28:17Z","updated_at":"2017-06-29T13:28:39Z","html_url":"https://github.com/akka/akka/pull/23239#discussion_r124798851","pull_request_url":"https://api.github.com/repos/akka/akka/pulls/23239","_links":{"self":{"href":"https://api.github.com/repos/akka/akka/pulls/comments/124798851"},"html":{"href":"https://github.com/akka/akka/pull/23239#discussion_r124798851"},"pull_request":{"href":"https://api.github.com/repos/akka/akka/pulls/23239"}}},"pull_request":{"url":"https://api.github.com/repos/akka/akka/pulls/23239","id":127657974,"html_url":"https://github.com/akka/akka/pull/23239","diff_url":"https://github.com/akka/akka/pull/23239.diff","patch_url":"https://github.com/akka/akka/pull/23239.patch","issue_url":"https://api.github.com/repos/akka/akka/issues/23239","number":23239,"state":"open","locked":false,"title":"[WIP] one leader per cluster team","user":{"login":"johanandren","id":666915,"avatar_url":"https://avatars0.githubusercontent.com/u/666915?v=3","gravatar_id":"","url":"https://api.github.com/users/johanandren","html_url":"https://github.com/johanandren","followers_url":"https://api.github.com/users/johanandren/followers","following_url":"https://api.github.com/users/johanandren/following{/other_user}","gists_url":"https://api.github.com/users/johanandren/gists{/gist_id}","starred_url":"https://api.github.com/users/johanandren/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/johanandren/subscriptions","organizations_url":"https://api.github.com/users/johanandren/orgs","repos_url":"https://api.github.com/users/johanandren/repos","events_url":"https://api.github.com/users/johanandren/events{/privacy}","received_events_url":"https://api.github.com/users/johanandren/received_events","type":"User","site_admin":false},"body":"Refs #23228 ","created_at":"2017-06-27T10:13:48Z","updated_at":"2017-06-29T13:28:39Z","closed_at":null,"merged_at":null,"merge_commit_sha":"b8f39e4535a685c45706503ccc3a5d5ffdbfb6ab","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/akka/akka/pulls/23239/commits","review_comments_url":"https://api.github.com/repos/akka/akka/pulls/23239/comments","review_comment_url":"https://api.github.com/repos/akka/akka/pulls/comments{/number}","comments_url":"https://api.github.com/repos/akka/akka/issues/23239/comments","statuses_url":"https://api.github.com/repos/akka/akka/statuses/d47a701d6074aac3371c9233e5f6310224669165","head":{"label":"johanandren:wip-23228-cluster-teams-leader-johanandren","ref":"wip-23228-cluster-teams-leader-johanandren","sha":"d47a701d6074aac3371c9233e5f6310224669165","user":{"login":"johanandren","id":666915,"avatar_url":"https://avatars0.githubusercontent.com/u/666915?v=3","gravatar_id":"","url":"https://api.github.com/users/johanandren","html_url":"https://github.com/johanandren","followers_url":"https://api.github.com/users/johanandren/followers","following_url":"https://api.github.com/users/johanandren/following{/other_user}","gists_url":"https://api.github.com/users/johanandren/gists{/gist_id}","starred_url":"https://api.github.com/users/johanandren/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/johanandren/subscriptions","organizations_url":"https://api.github.com/users/johanandren/orgs","repos_url":"https://api.github.com/users/johanandren/repos","events_url":"https://api.github.com/users/johanandren/events{/privacy}","received_events_url":"https://api.github.com/users/johanandren/received_events","type":"User","site_admin":false},"repo":{"id":41662207,"name":"akka","full_name":"johanandren/akka","owner":{"login":"johanandren","id":666915,"avatar_url":"https://avatars0.githubusercontent.com/u/666915?v=3","gravatar_id":"","url":"https://api.github.com/users/johanandren","html_url":"https://github.com/johanandren","followers_url":"https://api.github.com/users/johanandren/followers","following_url":"https://api.github.com/users/johanandren/following{/other_user}","gists_url":"https://api.github.com/users/johanandren/gists{/gist_id}","starred_url":"https://api.github.com/users/johanandren/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/johanandren/subscriptions","organizations_url":"https://api.github.com/users/johanandren/orgs","repos_url":"https://api.github.com/users/johanandren/repos","events_url":"https://api.github.com/users/johanandren/events{/privacy}","received_events_url":"https://api.github.com/users/johanandren/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/johanandren/akka","description":"Akka Project","fork":true,"url":"https://api.github.com/repos/johanandren/akka","forks_url":"https://api.github.com/repos/johanandren/akka/forks","keys_url":"https://api.github.com/repos/johanandren/akka/keys{/key_id}","collaborators_url":"https://api.github.com/repos/johanandren/akka/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/johanandren/akka/teams","hooks_url":"https://api.github.com/repos/johanandren/akka/hooks","issue_events_url":"https://api.github.com/repos/johanandren/akka/issues/events{/number}","events_url":"https://api.github.com/repos/johanandren/akka/events","assignees_url":"https://api.github.com/repos/johanandren/akka/assignees{/user}","branches_url":"https://api.github.com/repos/johanandren/akka/branches{/branch}","tags_url":"https://api.github.com/repos/johanandren/akka/tags","blobs_url":"https://api.github.com/repos/johanandren/akka/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/johanandren/akka/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/johanandren/akka/git/refs{/sha}","trees_url":"https://api.github.com/repos/johanandren/akka/git/trees{/sha}","statuses_url":"https://api.github.com/repos/johanandren/akka/statuses/{sha}","languages_url":"https://api.github.com/repos/johanandren/akka/languages","stargazers_url":"https://api.github.com/repos/johanandren/akka/stargazers","contributors_url":"https://api.github.com/repos/johanandren/akka/contributors","subscribers_url":"https://api.github.com/repos/johanandren/akka/subscribers","subscription_url":"https://api.github.com/repos/johanandren/akka/subscription","commits_url":"https://api.github.com/repos/johanandren/akka/commits{/sha}","git_commits_url":"https://api.github.com/repos/johanandren/akka/git/commits{/sha}","comments_url":"https://api.github.com/repos/johanandren/akka/comments{/number}","issue_comment_url":"https://api.github.com/repos/johanandren/akka/issues/comments{/number}","contents_url":"https://api.github.com/repos/johanandren/akka/contents/{+path}","compare_url":"https://api.github.com/repos/johanandren/akka/compare/{base}...{head}","merges_url":"https://api.github.com/repos/johanandren/akka/merges","archive_url":"https://api.github.com/repos/johanandren/akka/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/johanandren/akka/downloads","issues_url":"https://api.github.com/repos/johanandren/akka/issues{/number}","pulls_url":"https://api.github.com/repos/johanandren/akka/pulls{/number}","milestones_url":"https://api.github.com/repos/johanandren/akka/milestones{/number}","notifications_url":"https://api.github.com/repos/johanandren/akka/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/johanandren/akka/labels{/name}","releases_url":"https://api.github.com/repos/johanandren/akka/releases{/id}","deployments_url":"https://api.github.com/repos/johanandren/akka/deployments","created_at":"2015-08-31T07:37:07Z","updated_at":"2016-02-02T08:15:23Z","pushed_at":"2017-06-29T12:24:42Z","git_url":"git://github.com/johanandren/akka.git","ssh_url":"git@github.com:johanandren/akka.git","clone_url":"https://github.com/johanandren/akka.git","svn_url":"https://github.com/johanandren/akka","homepage":"http://akka.io","size":202976,"stargazers_count":0,"watchers_count":0,"language":"Scala","has_issues":false,"has_projects":true,"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":"akka:master","ref":"master","sha":"1b1b8258657f47549d778eaf8707428e90d93d0c","user":{"login":"akka","id":1496237,"avatar_url":"https://avatars1.githubusercontent.com/u/1496237?v=3","gravatar_id":"","url":"https://api.github.com/users/akka","html_url":"https://github.com/akka","followers_url":"https://api.github.com/users/akka/followers","following_url":"https://api.github.com/users/akka/following{/other_user}","gists_url":"https://api.github.com/users/akka/gists{/gist_id}","starred_url":"https://api.github.com/users/akka/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/akka/subscriptions","organizations_url":"https://api.github.com/users/akka/orgs","repos_url":"https://api.github.com/users/akka/repos","events_url":"https://api.github.com/users/akka/events{/privacy}","received_events_url":"https://api.github.com/users/akka/received_events","type":"Organization","site_admin":false},"repo":{"id":130013,"name":"akka","full_name":"akka/akka","owner":{"login":"akka","id":1496237,"avatar_url":"https://avatars1.githubusercontent.com/u/1496237?v=3","gravatar_id":"","url":"https://api.github.com/users/akka","html_url":"https://github.com/akka","followers_url":"https://api.github.com/users/akka/followers","following_url":"https://api.github.com/users/akka/following{/other_user}","gists_url":"https://api.github.com/users/akka/gists{/gist_id}","starred_url":"https://api.github.com/users/akka/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/akka/subscriptions","organizations_url":"https://api.github.com/users/akka/orgs","repos_url":"https://api.github.com/users/akka/repos","events_url":"https://api.github.com/users/akka/events{/privacy}","received_events_url":"https://api.github.com/users/akka/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/akka/akka","description":"Build highly concurrent, distributed, and resilient message-driven applications on the JVM","fork":false,"url":"https://api.github.com/repos/akka/akka","forks_url":"https://api.github.com/repos/akka/akka/forks","keys_url":"https://api.github.com/repos/akka/akka/keys{/key_id}","collaborators_url":"https://api.github.com/repos/akka/akka/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/akka/akka/teams","hooks_url":"https://api.github.com/repos/akka/akka/hooks","issue_events_url":"https://api.github.com/repos/akka/akka/issues/events{/number}","events_url":"https://api.github.com/repos/akka/akka/events","assignees_url":"https://api.github.com/repos/akka/akka/assignees{/user}","branches_url":"https://api.github.com/repos/akka/akka/branches{/branch}","tags_url":"https://api.github.com/repos/akka/akka/tags","blobs_url":"https://api.github.com/repos/akka/akka/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/akka/akka/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/akka/akka/git/refs{/sha}","trees_url":"https://api.github.com/repos/akka/akka/git/trees{/sha}","statuses_url":"https://api.github.com/repos/akka/akka/statuses/{sha}","languages_url":"https://api.github.com/repos/akka/akka/languages","stargazers_url":"https://api.github.com/repos/akka/akka/stargazers","contributors_url":"https://api.github.com/repos/akka/akka/contributors","subscribers_url":"https://api.github.com/repos/akka/akka/subscribers","subscription_url":"https://api.github.com/repos/akka/akka/subscription","commits_url":"https://api.github.com/repos/akka/akka/commits{/sha}","git_commits_url":"https://api.github.com/repos/akka/akka/git/commits{/sha}","comments_url":"https://api.github.com/repos/akka/akka/comments{/number}","issue_comment_url":"https://api.github.com/repos/akka/akka/issues/comments{/number}","contents_url":"https://api.github.com/repos/akka/akka/contents/{+path}","compare_url":"https://api.github.com/repos/akka/akka/compare/{base}...{head}","merges_url":"https://api.github.com/repos/akka/akka/merges","archive_url":"https://api.github.com/repos/akka/akka/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/akka/akka/downloads","issues_url":"https://api.github.com/repos/akka/akka/issues{/number}","pulls_url":"https://api.github.com/repos/akka/akka/pulls{/number}","milestones_url":"https://api.github.com/repos/akka/akka/milestones{/number}","notifications_url":"https://api.github.com/repos/akka/akka/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/akka/akka/labels{/name}","releases_url":"https://api.github.com/repos/akka/akka/releases{/id}","deployments_url":"https://api.github.com/repos/akka/akka/deployments","created_at":"2009-02-16T12:51:54Z","updated_at":"2017-06-29T12:16:36Z","pushed_at":"2017-06-29T12:24:44Z","git_url":"git://github.com/akka/akka.git","ssh_url":"git@github.com:akka/akka.git","clone_url":"https://github.com/akka/akka.git","svn_url":"https://github.com/akka/akka","homepage":"http://akka.io","size":201614,"stargazers_count":7293,"watchers_count":7293,"language":"Scala","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":2306,"mirror_url":null,"open_issues_count":576,"forks":2306,"open_issues":576,"watchers":7293,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/akka/akka/pulls/23239"},"html":{"href":"https://github.com/akka/akka/pull/23239"},"issue":{"href":"https://api.github.com/repos/akka/akka/issues/23239"},"comments":{"href":"https://api.github.com/repos/akka/akka/issues/23239/comments"},"review_comments":{"href":"https://api.github.com/repos/akka/akka/pulls/23239/comments"},"review_comment":{"href":"https://api.github.com/repos/akka/akka/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/akka/akka/pulls/23239/commits"},"statuses":{"href":"https://api.github.com/repos/akka/akka/statuses/d47a701d6074aac3371c9233e5f6310224669165"}}}}
{"actor":{"display_login":"patriknw"}}