Class: Bitfab::HttpClient
- Inherits:
-
Object
- Object
- Bitfab::HttpClient
- Defined in:
- lib/bitfab/http_client.rb
Instance Attribute Summary collapse
-
#service_url ⇒ Object
readonly
Returns the value of attribute service_url.
Instance Method Summary collapse
-
#complete_replay(test_run_id) ⇒ Object
Mark a replay test run as completed.
-
#get(endpoint, timeout: nil) ⇒ Object
Make a GET request to the Bitfab API.
-
#get_external_span(span_id) ⇒ Object
Fetch an external span by ID.
-
#get_span_tree(external_span_id) ⇒ Object
Fetch the span tree rooted at an external span.
-
#initialize(api_key:, service_url: nil, timeout: 120) ⇒ HttpClient
constructor
A new instance of HttpClient.
-
#release_db_branch_lease(neon_branch_id) ⇒ Object
Release a previously-resolved DB branch by deleting its Neon branch.
-
#request(endpoint, payload, timeout: nil, max_retries: 1, retry_delay: 0.1) ⇒ Object
Make a POST request to the Bitfab API.
-
#send_external_span(payload) ⇒ Object
Send an external span in a background thread.
-
#send_external_trace(payload) ⇒ Object
Send an external trace (fire-and-forget in background thread).
-
#start_replay(trace_function_key, limit, trace_ids: nil, code_change_description: nil, code_change_files: nil, experiment_group_id: nil, name: nil, include_db_branch_lease: false, dataset_id: nil) ⇒ Object
Start a replay session by fetching historical traces.
Constructor Details
#initialize(api_key:, service_url: nil, timeout: 120) ⇒ HttpClient
Returns a new instance of HttpClient.
16 17 18 19 20 |
# File 'lib/bitfab/http_client.rb', line 16 def initialize(api_key:, service_url: nil, timeout: 120) @api_key = api_key @service_url = (service_url || DEFAULT_SERVICE_URL).chomp("/") @timeout = timeout end |
Instance Attribute Details
#service_url ⇒ Object (readonly)
Returns the value of attribute service_url.
14 15 16 |
# File 'lib/bitfab/http_client.rb', line 14 def service_url @service_url end |
Instance Method Details
#complete_replay(test_run_id) ⇒ Object
Mark a replay test run as completed. Blocking call.
155 156 157 |
# File 'lib/bitfab/http_client.rb', line 155 def complete_replay(test_run_id) request("/api/sdk/replay/complete", {"testRunId" => test_run_id}, timeout: 30) end |
#get(endpoint, timeout: nil) ⇒ Object
Make a GET request to the Bitfab API. Returns parsed JSON response hash.
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/bitfab/http_client.rb', line 74 def get(endpoint, timeout: nil) uri = URI("#{@service_url}#{endpoint}") request_timeout = timeout || @timeout http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = uri.scheme == "https" http.open_timeout = request_timeout http.read_timeout = request_timeout req = Net::HTTP::Get.new(uri.path, headers) response = http.request(req) unless response.is_a?(Net::HTTPSuccess) raise Net::HTTPError.new("HTTP #{response.code}: #{response.body}", response) end result = JSON.parse(response.body) if result["error"] msg = result["error"] msg = "#{msg} Configure it at: #{@service_url}#{result["url"]}" if result["url"] raise StandardError, msg end result end |
#get_external_span(span_id) ⇒ Object
Fetch an external span by ID. Blocking GET request.
139 140 141 |
# File 'lib/bitfab/http_client.rb', line 139 def get_external_span(span_id) get("/api/sdk/externalSpans/#{span_id}", timeout: 30) end |
#get_span_tree(external_span_id) ⇒ Object
Fetch the span tree rooted at an external span. Blocking GET request. Used by replay when a mock strategy is active so child spans can be matched against their historical outputs.
Returns a hash shaped { “root” => SpanTreeNode } where each node has sourceSpanId, traceFunctionKey, spanName, type, output, optional outputMeta, and children.
150 151 152 |
# File 'lib/bitfab/http_client.rb', line 150 def get_span_tree(external_span_id) get("/api/sdk/replay/spanTree/#{external_span_id}", timeout: 30) end |
#release_db_branch_lease(neon_branch_id) ⇒ Object
Release a previously-resolved DB branch by deleting its Neon branch. Blocking call. Idempotent server-side (a missing branch is treated as already released).
162 163 164 |
# File 'lib/bitfab/http_client.rb', line 162 def release_db_branch_lease(neon_branch_id) request("/api/sdk/replay/releaseDbBranchLease", {"neonBranchId" => neon_branch_id}, timeout: 30) end |
#request(endpoint, payload, timeout: nil, max_retries: 1, retry_delay: 0.1) ⇒ Object
Make a POST request to the Bitfab API. Returns parsed JSON response hash.
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/bitfab/http_client.rb', line 24 def request(endpoint, payload, timeout: nil, max_retries: 1, retry_delay: 0.1) uri = URI("#{@service_url}#{endpoint}") request_timeout = timeout || @timeout last_error = nil max_retries.times do |attempt| http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = uri.scheme == "https" http.open_timeout = request_timeout http.read_timeout = request_timeout req = Net::HTTP::Post.new(uri.path, headers) req.body = safe_generate(payload, endpoint) response = http.request(req) unless response.is_a?(Net::HTTPSuccess) raise Net::HTTPError.new("HTTP #{response.code}: #{response.body}", response) end result = JSON.parse(response.body) if result["error"] msg = result["error"] msg = "#{msg} Configure it at: #{@service_url}#{result["url"]}" if result["url"] raise StandardError, msg end return result rescue => e last_error = e sleep(retry_delay) if attempt < max_retries - 1 end raise last_error end |
#send_external_span(payload) ⇒ Object
Send an external span in a background thread. Returns the thread for callers that need to await completion.
64 65 66 67 68 69 70 |
# File 'lib/bitfab/http_client.rb', line 64 def send_external_span(payload) merged = payload.merge("sdkVersion" => VERSION) Bitfab._run_in_background do request("/api/sdk/externalSpans", merged, timeout: 30) end end |
#send_external_trace(payload) ⇒ Object
Send an external trace (fire-and-forget in background thread).
167 168 169 170 171 172 173 |
# File 'lib/bitfab/http_client.rb', line 167 def send_external_trace(payload) merged = payload.merge("sdkVersion" => VERSION) Bitfab._run_in_background do request("/api/sdk/externalTraces", merged, timeout: 10) end end |
#start_replay(trace_function_key, limit, trace_ids: nil, code_change_description: nil, code_change_files: nil, experiment_group_id: nil, name: nil, include_db_branch_lease: false, dataset_id: nil) ⇒ Object
Start a replay session by fetching historical traces. Blocking call. Returns hash with testRunId, testRunUrl, and items array.
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/bitfab/http_client.rb', line 114 def start_replay(trace_function_key, limit, trace_ids: nil, code_change_description: nil, code_change_files: nil, experiment_group_id: nil, name: nil, include_db_branch_lease: false, dataset_id: nil) payload = { "traceFunctionKey" => trace_function_key } # limit is only meaningful without trace_ids (an explicit ID list # already determines the count), so it's omitted when nil. payload["limit"] = limit unless limit.nil? payload["traceIds"] = trace_ids if trace_ids payload["name"] = name unless name.nil? payload["codeChangeDescription"] = code_change_description unless code_change_description.nil? payload["codeChangeFiles"] = normalize_code_change_files(code_change_files) unless code_change_files.nil? payload["experimentGroupId"] = experiment_group_id unless experiment_group_id.nil? payload["includeDbBranchLease"] = true if include_db_branch_lease payload["datasetId"] = dataset_id unless dataset_id.nil? # When DB branching is on, the server resolves a Neon preview branch per # item (snapshot + restore + poll), which can run several seconds each. # Use a generous timeout so the SDK doesn't give up before a healthy # server finishes. timeout = include_db_branch_lease ? 180 : 30 request("/api/sdk/replay/start", payload, timeout:) end |