From 5a4fee0e23b36db1961db42e392c17991e586d5e Mon Sep 17 00:00:00 2001 From: Andrew Ho Date: Thu, 26 Feb 2026 10:43:40 -0800 Subject: [PATCH] Configurable brokerService for console queries --- .../router/TieredBrokerHostSelector.java | 2 +- web-console/src/entry.tsx | 10 ++++- web-console/src/utils/druid-query.ts | 37 ++++++++++++++++++- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/services/src/main/java/org/apache/druid/server/router/TieredBrokerHostSelector.java b/services/src/main/java/org/apache/druid/server/router/TieredBrokerHostSelector.java index e1732b44fb20..6a20f3bb418d 100644 --- a/services/src/main/java/org/apache/druid/server/router/TieredBrokerHostSelector.java +++ b/services/src/main/java/org/apache/druid/server/router/TieredBrokerHostSelector.java @@ -287,7 +287,7 @@ public Pair selectForSql(SqlQuery sqlQuery) } } - // Use defaut if not resolved by strategies + // Use default if not resolved by strategies if (brokerServiceName == null) { brokerServiceName = tierConfig.getDefaultBrokerServiceName(); diff --git a/web-console/src/entry.tsx b/web-console/src/entry.tsx index e441a3ec5bec..3bf438e73c5f 100644 --- a/web-console/src/entry.tsx +++ b/web-console/src/entry.tsx @@ -30,7 +30,7 @@ import type { QueryContext } from './druid-models'; import type { Links } from './links'; import { setLinkOverrides } from './links'; import { Api, UrlBaser } from './singletons'; -import { initMouseTooltip, setLocalStorageNamespace } from './utils'; +import { initMouseTooltip, setConsoleBrokerService, setLocalStorageNamespace } from './utils'; import './entry.scss'; @@ -70,6 +70,10 @@ interface ConsoleConfig { // Allow for namespacing the local storage in case multiple clusters share a URL due to proxying localStorageNamespace?: string; + + // Broker service name to use for all console SQL queries (for tier isolation) + // This injects "brokerService" into the query context for routing via the manual strategy + consoleBrokerService?: string; } const consoleConfig: ConsoleConfig = (window as any).consoleConfig; @@ -101,6 +105,10 @@ if (consoleConfig.localStorageNamespace) { setLocalStorageNamespace(consoleConfig.localStorageNamespace); } +if (consoleConfig.consoleBrokerService) { + setConsoleBrokerService(consoleConfig.consoleBrokerService); +} + QueryRunner.defaultQueryExecutor = ({ payload, isSql, signal }) => { return Api.instance.post(`/druid/v2${isSql ? '/sql' : ''}`, payload, { signal }); }; diff --git a/web-console/src/utils/druid-query.ts b/web-console/src/utils/druid-query.ts index c4e04c37162f..8a8175a2fc7a 100644 --- a/web-console/src/utils/druid-query.ts +++ b/web-console/src/utils/druid-query.ts @@ -322,13 +322,35 @@ export class DruidError extends Error { } } +// Broker service to use for all console queries (for tier isolation) +let consoleBrokerService: string | undefined; + +export function setConsoleBrokerService(brokerService: string | undefined): void { + consoleBrokerService = brokerService; +} + +export function getConsoleBrokerService(): string | undefined { + return consoleBrokerService; +} + export async function queryDruidRune( runeQuery: Record, signal?: AbortSignal, ): Promise { let runeResultResp: AxiosResponse; try { - runeResultResp = await Api.instance.post('/druid/v2', runeQuery, { signal }); + // Inject brokerService into context if configured + const query = consoleBrokerService + ? { + ...runeQuery, + context: { + ...runeQuery.context, + brokerService: consoleBrokerService, + }, + } + : runeQuery; + + runeResultResp = await Api.instance.post('/druid/v2', query, { signal }); } catch (e) { throw new Error(getDruidErrorMessage(e)); } @@ -341,7 +363,18 @@ export async function queryDruidSql( ): Promise { let sqlResultResp: AxiosResponse; try { - sqlResultResp = await Api.instance.post('/druid/v2/sql', sqlQueryPayload, { signal }); + // Inject brokerService into context if configured + const payload = consoleBrokerService + ? { + ...sqlQueryPayload, + context: { + ...sqlQueryPayload.context, + brokerService: consoleBrokerService, + }, + } + : sqlQueryPayload; + + sqlResultResp = await Api.instance.post('/druid/v2/sql', payload, { signal }); } catch (e) { throw new Error(getDruidErrorMessage(e)); }