diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/FederationInterceptorREST.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/FederationInterceptorREST.java index 48cb41775bdce..285e231619949 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/FederationInterceptorREST.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/FederationInterceptorREST.java @@ -2341,9 +2341,9 @@ private Map invokeConcurrent(Collection c throw exception; } } catch (Throwable e) { - String msg = String.format("SubCluster %s failed to %s report.", subClusterInfo, - request.getMethodName()); - LOG.error(msg, e); + String subClusterId = subClusterInfo != null ? + subClusterInfo.getSubClusterId().getId() : "UNKNOWN"; + LOG.error("SubCluster {} failed to {} report.", subClusterId, request.getMethodName(), e); throw new YarnRuntimeException(e.getCause().getMessage(), e); } } @@ -2417,4 +2417,17 @@ public Map getInterceptors() { public void setAllowPartialResult(boolean allowPartialResult) { this.allowPartialResult = allowPartialResult; } + + @VisibleForTesting + public Map invokeConcurrentGetNodeLabel() + throws IOException, YarnException { + NodesInfo nodes = new NodesInfo(); + Map subClustersActive = getActiveSubclusters(); + Class[] argsClasses = new Class[]{String.class}; + Object[] args = new Object[]{null}; + ClientMethod remoteMethod = new ClientMethod("getNodes", argsClasses, args); + Map nodesMap = + invokeConcurrent(subClustersActive.values(), remoteMethod, NodesInfo.class); + return nodesMap; + } } \ No newline at end of file diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/test/java/org/apache/hadoop/yarn/server/router/webapp/TestFederationInterceptorREST.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/test/java/org/apache/hadoop/yarn/server/router/webapp/TestFederationInterceptorREST.java index 14533d10871ac..a1daf458a72b2 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/test/java/org/apache/hadoop/yarn/server/router/webapp/TestFederationInterceptorREST.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/test/java/org/apache/hadoop/yarn/server/router/webapp/TestFederationInterceptorREST.java @@ -1485,4 +1485,32 @@ public void testCheckFederationInterceptorRESTClient() { Assert.assertNotNull(interceptorREST.getClient()); Assert.assertEquals(webAppAddress, interceptorREST.getWebAppAddress()); } + + @Test + public void testInvokeConcurrent() throws IOException, YarnException { + + // We design such a test case, we call the interceptor's getNodes interface, + // this interface will generate the following test data + // subCluster0 Node 0 + // subCluster1 Node 1 + // subCluster2 Node 2 + // subCluster3 Node 3 + // We use the returned data to verify whether the subClusterId + // of the multi-thread call can match the node data + Map subClusterInfoNodesInfoMap = + interceptor.invokeConcurrentGetNodeLabel(); + Assert.assertNotNull(subClusterInfoNodesInfoMap); + Assert.assertEquals(4, subClusterInfoNodesInfoMap.size()); + + subClusterInfoNodesInfoMap.forEach((subClusterInfo, nodesInfo) -> { + String subClusterId = subClusterInfo.getSubClusterId().getId(); + List nodeInfos = nodesInfo.getNodes(); + Assert.assertNotNull(nodeInfos); + Assert.assertEquals(1, nodeInfos.size()); + + String expectNodeId = "Node " + subClusterId; + String nodeId = nodeInfos.get(0).getNodeId(); + Assert.assertEquals(expectNodeId, nodeId); + }); + } } \ No newline at end of file