@@ -11,56 +11,26 @@ module Internal
1111 # Internal BTQL client for querying spans.
1212 # Not part of the public API — instantiated directly where needed.
1313 class BTQL
14- # Maximum number of retries before returning partial results.
15- # Covers both freshness lag (partially indexed) and ingestion lag
16- # (spans not yet visible to BTQL after OTel flush).
17- MAX_FRESHNESS_RETRIES = 7
18-
19- # Base delay (seconds) between retries (doubles each attempt, capped).
20- FRESHNESS_BASE_DELAY = 1.0
21-
22- # Maximum delay (seconds) between retries. Caps exponential growth
23- # so we keep polling at a reasonable rate in the later window.
24- # Schedule: 1, 2, 4, 8, 8, 8, 8 = ~39s total worst-case.
25- MAX_FRESHNESS_DELAY = 8.0
26-
2714 def initialize ( state )
2815 @state = state
2916 end
3017
3118 # Query spans belonging to a specific trace within an object.
3219 #
3320 # Builds a BTQL SQL query that matches the root_span_id and excludes scorer spans.
34- # Retries with exponential backoff if the response indicates data is not yet fresh .
21+ # Returns a single-shot result; callers are responsible for retry and error handling .
3522 #
3623 # @param object_type [String] e.g. "experiment"
3724 # @param object_id [String] Object UUID
3825 # @param root_span_id [String] Hex trace ID of the root span
39- # @return [Array<Hash>] Parsed span data
26+ # @return [Array(Array <Hash>, String)] [rows, freshness]
4027 def trace_spans ( object_type :, object_id :, root_span_id :)
4128 query = build_trace_query (
4229 object_type : object_type ,
4330 object_id : object_id ,
4431 root_span_id : root_span_id
4532 )
46- payload = { query : query , fmt : "jsonl" }
47-
48- retries = 0
49- loop do
50- rows , freshness = execute_query ( payload )
51- # Return when data is fresh AND non-empty, or we've exhausted retries.
52- # We retry on empty even when "complete" because there is ingestion lag
53- # between OTel flush and BTQL indexing — the server may report "complete"
54- # before it knows about newly-flushed spans.
55- return rows if ( freshness == "complete" && !rows . empty? ) || retries >= MAX_FRESHNESS_RETRIES
56-
57- retries += 1
58- delay = [ FRESHNESS_BASE_DELAY * ( 2 **( retries - 1 ) ) , MAX_FRESHNESS_DELAY ] . min
59- sleep ( delay )
60- end
61- rescue => e
62- Braintrust ::Log . warn ( "[BTQL] Query failed: #{ e . message } " )
63- [ ]
33+ execute_query ( query : query , fmt : "jsonl" )
6434 end
6535
6636 private
0 commit comments