Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions data_plane/src/drivers/query/servers/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -945,6 +945,64 @@ async fn process_via_simple_engine(
Err(status) => status.into_response()}
}
None => {
// Legacy `handle_query` returned None — likely the
// sketch-vs-precompute query gap pinned in #252:
// `query_precomputes_by_agg` only picks up
// `AggKind::ExactAgg` sids, never `AggKind::Sketch`. Try
// the modern `ASAPQueryEngine::execute(&str)` trait path
// before falling through to the unsupported-query branch
// — `execute` uses
// `idx.sids_for_policy(fp)` + `SketchReducer::evaluate`
// and handles sketches natively.
//
// Trait dispatch loses `KeyByLabelNames` (the trait
// returns just `QueryResult`); we surface an empty
// `KeyByLabelNames`, identical to how `process_via_router`
// handles the same trait surface — the Prometheus
// adapter renders an empty `metric: {}` object, a valid
// shape that PromQL clients accept.
use crate::query_engines::routing::query_engine_routing::QueryEngine;
let modern_result = state
.query_engine
.execute(&parsed_request.query)
.await;
if let Ok(query_result) = modern_result {
debug!(
"Modern execute() handled what legacy handle_query missed \
(query='{}')",
parsed_request.query
);
use crate::drivers::query::adapters::QueryExecutionResult;
let execution_result = QueryExecutionResult {
query_output_labels: promql_utilities::data_model::KeyByLabelNames::default(),
query_result,
};
let total_duration = start_time.elapsed();
debug!(
"Total request processing took (modern fallback): {:.2}ms",
total_duration.as_secs_f64() * 1000.0
);
return match state
.adapter
.format_success_response(&execution_result)
.await
{
Ok(response) => {
annotate_data_source(
response,
StorageBackend::SketchStore.data_source_id(),
)
.await
}
Err(status) => status.into_response(),
};
}
debug!(
"Both legacy handle_query AND modern execute() returned None/Err for \
query='{}', falling through to fallback / unsupported",
parsed_request.query
);

let total_duration = start_time.elapsed();
debug!("=== QUERY ENGINE RETURNED NONE ===");
debug!(
Expand Down
33 changes: 24 additions & 9 deletions data_plane/tests/e2e_controller_plans_and_backend_serves.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,11 @@ async fn start_backend_http_server() -> (u16, HotReloadStreamingConfig) {
use data_plane::storage_engines::types::StreamingConfig;

let hot_reload = HotReloadStreamingConfig::new(StreamingConfig::default());
let query_engine = Arc::new(ASAPQueryEngine::new_with_hot_reload(
hot_reload.clone(),
15_000,
));
let sketch_index = Arc::new(SketchStore::new());
let query_engine = Arc::new(
ASAPQueryEngine::new_with_hot_reload(hot_reload.clone(), 15_000)
.with_sketch_index(sketch_index.clone()),
);

let adapter_config = AdapterConfig::prometheus_promql(
"http://127.0.0.1:9999".to_string(), // unused — no forwarding in this test
Expand All @@ -145,7 +146,6 @@ async fn start_backend_http_server() -> (u16, HotReloadStreamingConfig) {
adapter_config,
};

let sketch_index = Arc::new(SketchStore::new());
let server = HttpServer::new(http_config, query_engine, sketch_index)
.with_hot_reload_config(hot_reload.clone());

Expand Down Expand Up @@ -283,10 +283,16 @@ async fn start_full_stack(otlp_http_port: u16, otlp_grpc_port: u16) -> FullStack
handle_http_requests: true,
adapter_config,
};
let query_engine = Arc::new(ASAPQueryEngine::new_with_hot_reload(
hot_reload.clone(),
15_000,
));
let query_engine = Arc::new(
ASAPQueryEngine::new_with_hot_reload(hot_reload.clone(), 15_000)
// CRITICAL: without this the engine's `sketch_index` is
// None and every fast path that reads sid → SketchInstance
// metadata is silently skipped. Sketches DO land in
// `sketch_index` via OTLP ingest (the engine's
// `precompute_engine` shares the Arc), but the query
// path can't see them without this binding.
.with_sketch_index(sketch_index.clone()),
);
let server = HttpServer::new(http_config, query_engine, sketch_index)
.with_hot_reload_config(hot_reload.clone());
let backend_port = server
Expand Down Expand Up @@ -704,4 +710,13 @@ async fn controller_plan_to_query_full_roundtrip_ddsketch() {
"PromQL response missing `status` field — HTTP layer is unhealthy\n{}",
serde_json::to_string_pretty(&response).unwrap_or_default()
);
let status = response["status"].as_str().unwrap_or("(missing)");
assert_eq!(
status, "success",
"PromQL query did not succeed after the modern-execute() fallback in \
process_via_simple_engine. The legacy handle_query path can't read \
sketch-backed sids (#252), but the fallback should now reach them via \
the trait-dispatch path. Response:\n{}",
serde_json::to_string_pretty(&response).unwrap_or_default()
);
}