Skip to content

Commit b7ac0bf

Browse files
authored
fix: make BrokerDynamicConfig backwards-compatible (#19120)
Make BrokerDynamicConfig backwards-compatible. By default, brokers who poll coordinators without the broker dynamic config endpoint (and receive a 404) will return an empty BrokerDynamicConfig.
1 parent 3570e6c commit b7ac0bf

3 files changed

Lines changed: 54 additions & 9 deletions

File tree

server/src/main/java/org/apache/druid/client/coordinator/CoordinatorClient.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ public interface CoordinatorClient
105105
/**
106106
* Gets the latest broker dynamic config from the Coordinator.
107107
* Brokers use this to fetch their configuration from the Coordinator on startup.
108+
* Returns an empty {@link BrokerDynamicConfig} when querying older coordinators to ensure backwards-compatibility.
108109
* <p>
109110
* API: {@code GET /druid/coordinator/v1/broker/config}
110111
*/

server/src/main/java/org/apache/druid/client/coordinator/CoordinatorClientImpl.java

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.fasterxml.jackson.databind.ObjectMapper;
2424
import com.google.common.util.concurrent.Futures;
2525
import com.google.common.util.concurrent.ListenableFuture;
26+
import com.google.common.util.concurrent.MoreExecutors;
2627
import org.apache.druid.client.BootstrapSegmentsResponse;
2728
import org.apache.druid.client.ImmutableSegmentLoadInfo;
2829
import org.apache.druid.client.JsonParserIterator;
@@ -37,6 +38,7 @@
3738
import org.apache.druid.query.SegmentDescriptor;
3839
import org.apache.druid.query.lookup.LookupExtractorFactoryContainer;
3940
import org.apache.druid.query.lookup.LookupUtils;
41+
import org.apache.druid.rpc.HttpResponseException;
4042
import org.apache.druid.rpc.IgnoreHttpResponseHandler;
4143
import org.apache.druid.rpc.RequestBuilder;
4244
import org.apache.druid.rpc.ServiceClient;
@@ -257,16 +259,23 @@ public ListenableFuture<CoordinatorDynamicConfig> getCoordinatorDynamicConfig()
257259
@Override
258260
public ListenableFuture<BrokerDynamicConfig> getBrokerDynamicConfig()
259261
{
260-
return FutureUtils.transform(
261-
client.asyncRequest(
262-
new RequestBuilder(HttpMethod.GET, "/druid/coordinator/v1/broker/config"),
263-
new BytesFullResponseHandler()
262+
// Older coordinators may not support this endpoint; fall back to an empty config on 404.
263+
return Futures.catching(
264+
FutureUtils.transform(
265+
client.asyncRequest(
266+
new RequestBuilder(HttpMethod.GET, "/druid/coordinator/v1/broker/config"),
267+
new BytesFullResponseHandler()
268+
),
269+
holder -> JacksonUtils.readValue(jsonMapper, holder.getContent(), BrokerDynamicConfig.class)
264270
),
265-
holder -> JacksonUtils.readValue(
266-
jsonMapper,
267-
holder.getContent(),
268-
BrokerDynamicConfig.class
269-
)
271+
HttpResponseException.class,
272+
e -> {
273+
if (e != null && e.getResponse().getStatus().getCode() == 404) {
274+
return BrokerDynamicConfig.builder().build();
275+
}
276+
throw new RuntimeException(e);
277+
},
278+
MoreExecutors.directExecutor()
270279
);
271280
}
272281

server/src/test/java/org/apache/druid/client/coordinator/CoordinatorClientImplTest.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949
import org.apache.druid.segment.column.ColumnType;
5050
import org.apache.druid.segment.column.RowSignature;
5151
import org.apache.druid.segment.metadata.DataSourceInformation;
52+
import org.apache.druid.server.QueryBlocklistRule;
53+
import org.apache.druid.server.broker.BrokerDynamicConfig;
5254
import org.apache.druid.server.compaction.CompactionStatusResponse;
5355
import org.apache.druid.server.coordination.DruidServerMetadata;
5456
import org.apache.druid.server.coordination.ServerType;
@@ -832,4 +834,37 @@ public void test_updateRulesForDatasource() throws Exception
832834

833835
Assert.assertNull(coordinatorClient.updateRulesForDatasource("xyz", rules).get());
834836
}
837+
838+
@Test
839+
public void test_getBrokerDynamicConfig() throws Exception
840+
{
841+
final BrokerDynamicConfig brokerDynamicConfig = BrokerDynamicConfig.builder().withQueryBlocklist(
842+
List.of(
843+
new QueryBlocklistRule("test", Set.of("dataSource"), null, null)
844+
)
845+
).build();
846+
847+
serviceClient.expectAndRespond(
848+
new RequestBuilder(HttpMethod.GET, "/druid/coordinator/v1/broker/config"),
849+
HttpResponseStatus.OK,
850+
ImmutableMap.of(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON),
851+
jsonMapper.writeValueAsBytes(brokerDynamicConfig)
852+
);
853+
Assert.assertEquals(brokerDynamicConfig, coordinatorClient.getBrokerDynamicConfig().get());
854+
}
855+
856+
@Test
857+
public void test_getBrokerDynamicConfig_backwardsCompatibleCoordinatorRequest() throws Exception
858+
{
859+
serviceClient.expectAndThrow(
860+
new RequestBuilder(HttpMethod.GET, "/druid/coordinator/v1/broker/config"),
861+
new HttpResponseException(
862+
new StringFullResponseHolder(
863+
new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND),
864+
StandardCharsets.UTF_8
865+
)
866+
)
867+
);
868+
Assert.assertEquals(BrokerDynamicConfig.builder().build(), coordinatorClient.getBrokerDynamicConfig().get());
869+
}
835870
}

0 commit comments

Comments
 (0)