Fixing overlord issued too many redirects (#12908)

* Fixing race in overlord redirects where the node was redirecting to itself

* Fixing test cases
This commit is contained in:
Karan Kumar 2022-08-17 18:27:39 +05:30 committed by GitHub
parent f70f7b4b89
commit a3a9c5f409
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 40 additions and 25 deletions

View File

@ -232,6 +232,19 @@ public class TaskMaster implements TaskCountStatsProvider, TaskSlotCountStatsPro
return overlordLeaderSelector.getCurrentLeader(); return overlordLeaderSelector.getCurrentLeader();
} }
public Optional<String> getRedirectLocation()
{
String leader = overlordLeaderSelector.getCurrentLeader();
// do not redirect when
// leader is not elected
// leader is the current node
if (leader == null || leader.isEmpty() || overlordLeaderSelector.isLeader()) {
return Optional.absent();
} else {
return Optional.of(leader);
}
}
public Optional<TaskRunner> getTaskRunner() public Optional<TaskRunner> getTaskRunner()
{ {
if (isLeader()) { if (isLeader()) {

View File

@ -19,6 +19,7 @@
package org.apache.druid.indexing.overlord.http; package org.apache.druid.indexing.overlord.http;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.inject.Inject; import com.google.inject.Inject;
import org.apache.druid.indexing.overlord.TaskMaster; import org.apache.druid.indexing.overlord.TaskMaster;
@ -55,13 +56,12 @@ public class OverlordRedirectInfo implements RedirectInfo
public URL getRedirectURL(String queryString, String requestURI) public URL getRedirectURL(String queryString, String requestURI)
{ {
try { try {
final String leader = taskMaster.getCurrentLeader(); final Optional<String> redirectLocation = taskMaster.getRedirectLocation();
if (leader == null || leader.isEmpty()) { if (!redirectLocation.isPresent()) {
return null; return null;
} }
String location = StringUtils.format("%s%s", leader, requestURI); String location = StringUtils.format("%s%s", redirectLocation.get(), requestURI);
if (queryString != null) { if (queryString != null) {
location = StringUtils.format("%s?%s", location, queryString); location = StringUtils.format("%s?%s", location, queryString);
} }

View File

@ -19,6 +19,7 @@
package org.apache.druid.indexing.overlord.http; package org.apache.druid.indexing.overlord.http;
import com.google.common.base.Optional;
import org.apache.druid.indexing.overlord.TaskMaster; import org.apache.druid.indexing.overlord.TaskMaster;
import org.easymock.EasyMock; import org.easymock.EasyMock;
import org.junit.Assert; import org.junit.Assert;
@ -66,19 +67,9 @@ public class OverlordRedirectInfoTest
} }
@Test @Test
public void testGetRedirectURLNull() public void testGetRedirectURLWithEmptyLocation()
{ {
EasyMock.expect(taskMaster.getCurrentLeader()).andReturn(null).anyTimes(); EasyMock.expect(taskMaster.getRedirectLocation()).andReturn(Optional.absent()).anyTimes();
EasyMock.replay(taskMaster);
URL url = redirectInfo.getRedirectURL("query", "/request");
Assert.assertNull(url);
EasyMock.verify(taskMaster);
}
@Test
public void testGetRedirectURLEmpty()
{
EasyMock.expect(taskMaster.getCurrentLeader()).andReturn("").anyTimes();
EasyMock.replay(taskMaster); EasyMock.replay(taskMaster);
URL url = redirectInfo.getRedirectURL("query", "/request"); URL url = redirectInfo.getRedirectURL("query", "/request");
Assert.assertNull(url); Assert.assertNull(url);
@ -91,7 +82,7 @@ public class OverlordRedirectInfoTest
String host = "http://localhost"; String host = "http://localhost";
String query = "foo=bar&x=y"; String query = "foo=bar&x=y";
String request = "/request"; String request = "/request";
EasyMock.expect(taskMaster.getCurrentLeader()).andReturn(host).anyTimes(); EasyMock.expect(taskMaster.getRedirectLocation()).andReturn(Optional.of(host)).anyTimes();
EasyMock.replay(taskMaster); EasyMock.replay(taskMaster);
URL url = redirectInfo.getRedirectURL(query, request); URL url = redirectInfo.getRedirectURL(query, request);
Assert.assertEquals("http://localhost/request?foo=bar&x=y", url.toString()); Assert.assertEquals("http://localhost/request?foo=bar&x=y", url.toString());
@ -107,7 +98,7 @@ public class OverlordRedirectInfoTest
"UTF-8" "UTF-8"
) + "/status"; ) + "/status";
EasyMock.expect(taskMaster.getCurrentLeader()).andReturn(host).anyTimes(); EasyMock.expect(taskMaster.getRedirectLocation()).andReturn(Optional.of(host)).anyTimes();
EasyMock.replay(taskMaster); EasyMock.replay(taskMaster);
URL url = redirectInfo.getRedirectURL(null, request); URL url = redirectInfo.getRedirectURL(null, request);
Assert.assertEquals( Assert.assertEquals(

View File

@ -80,7 +80,6 @@ import org.junit.Test;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -217,6 +216,7 @@ public class OverlordTest
Thread.sleep(10); Thread.sleep(10);
} }
Assert.assertEquals(taskMaster.getCurrentLeader(), druidNode.getHostAndPort()); Assert.assertEquals(taskMaster.getCurrentLeader(), druidNode.getHostAndPort());
Assert.assertEquals(Optional.absent(), taskMaster.getRedirectLocation());
final TaskStorageQueryAdapter taskStorageQueryAdapter = new TaskStorageQueryAdapter(taskStorage, taskLockbox); final TaskStorageQueryAdapter taskStorageQueryAdapter = new TaskStorageQueryAdapter(taskStorage, taskLockbox);
final WorkerTaskRunnerQueryAdapter workerTaskRunnerQueryAdapter = new WorkerTaskRunnerQueryAdapter(taskMaster, null); final WorkerTaskRunnerQueryAdapter workerTaskRunnerQueryAdapter = new WorkerTaskRunnerQueryAdapter(taskMaster, null);

View File

@ -200,7 +200,12 @@ public class ServiceClientImpl implements ServiceClient
final String newUri = result.error().getResponse().headers().get("Location"); final String newUri = result.error().getResponse().headers().get("Location");
if (redirectCount >= MAX_REDIRECTS) { if (redirectCount >= MAX_REDIRECTS) {
retVal.setException(new RpcException("Service [%s] issued too many redirects", serviceName)); retVal.setException(new RpcException(
"Service [%s] redirected too many times [%d] to invalid url %s",
serviceName,
redirectCount,
newUri
));
} else { } else {
// Update preferredLocationNoPath if we got a redirect. // Update preferredLocationNoPath if we got a redirect.
final ServiceLocation redirectLocationNoPath = serviceLocationNoPathFromUri(newUri); final ServiceLocation redirectLocationNoPath = serviceLocationNoPathFromUri(newUri);
@ -212,7 +217,12 @@ public class ServiceClientImpl implements ServiceClient
); );
} else { } else {
retVal.setException( retVal.setException(
new RpcException("Service [%s] redirected to invalid URL [%s]", serviceName, newUri) new RpcException(
"Service [%s] redirected [%d] times to invalid URL [%s]",
serviceName,
redirectCount,
newUri
)
); );
} }
} }

View File

@ -289,7 +289,7 @@ public class ServiceClientImplTest
MatcherAssert.assertThat(e.getCause(), CoreMatchers.instanceOf(RpcException.class)); MatcherAssert.assertThat(e.getCause(), CoreMatchers.instanceOf(RpcException.class));
MatcherAssert.assertThat( MatcherAssert.assertThat(
e.getCause(), e.getCause(),
ThrowableMessageMatcher.hasMessage(CoreMatchers.containsString("too many redirects")) ThrowableMessageMatcher.hasMessage(CoreMatchers.containsString("redirected too many times"))
); );
} }
@ -313,7 +313,8 @@ public class ServiceClientImplTest
MatcherAssert.assertThat(e.getCause(), CoreMatchers.instanceOf(RpcException.class)); MatcherAssert.assertThat(e.getCause(), CoreMatchers.instanceOf(RpcException.class));
MatcherAssert.assertThat( MatcherAssert.assertThat(
e.getCause(), e.getCause(),
ThrowableMessageMatcher.hasMessage(CoreMatchers.containsString("redirected to invalid URL [invalid-url]")) ThrowableMessageMatcher.hasMessage(
CoreMatchers.containsString("redirected [0] times to invalid URL [invalid-url]"))
); );
} }
@ -337,7 +338,7 @@ public class ServiceClientImplTest
MatcherAssert.assertThat(e.getCause(), CoreMatchers.instanceOf(RpcException.class)); MatcherAssert.assertThat(e.getCause(), CoreMatchers.instanceOf(RpcException.class));
MatcherAssert.assertThat( MatcherAssert.assertThat(
e.getCause(), e.getCause(),
ThrowableMessageMatcher.hasMessage(CoreMatchers.containsString("redirected to invalid URL [null]")) ThrowableMessageMatcher.hasMessage(CoreMatchers.containsString("redirected [0] times to invalid URL [null]"))
); );
} }
@ -361,7 +362,7 @@ public class ServiceClientImplTest
MatcherAssert.assertThat(e.getCause(), CoreMatchers.instanceOf(RpcException.class)); MatcherAssert.assertThat(e.getCause(), CoreMatchers.instanceOf(RpcException.class));
MatcherAssert.assertThat( MatcherAssert.assertThat(
e.getCause(), e.getCause(),
ThrowableMessageMatcher.hasMessage(CoreMatchers.containsString("too many redirects")) ThrowableMessageMatcher.hasMessage(CoreMatchers.containsString("redirected too many times"))
); );
} }