class InteractionTracker
Tracks the completion of both request and response bodies for a single interaction. Records the interaction only when both sides are complete, capturing rich error context.
Definitions
def initialize(store, original_request)
Initialize the tracker.
Signature
-
parameter
store
Object
The store to record the interaction to.
-
parameter
original_request
Protocol::HTTP::Request
The original request.
Implementation
def initialize(store, original_request)
@store = store
@original_request = original_request
@original_response = nil
@request_complete = false
@response_complete = false
@request_body = nil
@response_body = nil
@error = nil
@clock = Async::Clock.start
# Will capture body as_json data at completion time for accurate state:
@debug_request_body = nil
@debug_response_body = nil
end
def mark_request_ready(request)
Mark the request as ready (no body to process).
Signature
-
parameter
request
Protocol::HTTP::Request
The request.
-
returns
Protocol::HTTP::Request
The same request.
Implementation
def mark_request_ready(request)
@request_complete = true
check_completion
request
end
def mark_response_ready(response)
Mark the response as ready (no body to process).
Signature
-
parameter
response
Protocol::HTTP::Response
The response.
-
returns
Protocol::HTTP::Response
The same response.
Implementation
def mark_response_ready(response)
@original_response = response
@response_complete = true
check_completion
response
end
def request_completed(body: nil, error: nil)
Called when request body processing completes.
Signature
-
parameter
body
Protocol::HTTP::Body::Buffered | Nil
The captured body.
-
parameter
error
Exception | Nil
Any error that occurred.
Implementation
def request_completed(body: nil, error: nil)
@request_complete = true
@request_body = body
# Capture as_json at completion time for accurate stateful information:
@debug_request_body = @original_request.body&.as_json
if error
@error = capture_error_context(error, :request_body)
end
check_completion
end
def response_completed(body: nil, error: nil)
Called when response body processing completes.
Signature
-
parameter
body
Protocol::HTTP::Body::Buffered | Nil
The captured body.
-
parameter
error
Exception | Nil
Any error that occurred.
Implementation
def response_completed(body: nil, error: nil)
@response_complete = true
@response_body = body
# Capture as_json at completion time for accurate stateful information:
@debug_response_body = @original_response&.body&.as_json
if error
@error = capture_error_context(error, :response_body)
end
check_completion
end
def set_response(response)
Set the response for this interaction.
Signature
-
parameter
response
Protocol::HTTP::Response
The response to associate.
Implementation
def set_response(response)
@original_response = response
end
def capture_error_context(error, phase)
Capture raw error context for post-processing analysis.
Signature
-
parameter
error
Exception
The error that occurred.
-
parameter
phase
Symbol
The phase where the error occurred.
-
returns
Hash
Raw error context data for external analysis.
Implementation
def capture_error_context(error, phase)
{
error_type: error.class.name,
error_message: error.message,
phase: phase,
elapsed_ms: (@clock.total * 1000).round(2),
timestamp: Time.now.iso8601
}
end
def check_completion
Check if both request and response are complete, and record if so.
Implementation
def check_completion
return unless @request_complete && @response_complete
# Create final request with buffered body:
final_request = ::Protocol::HTTP::Request.new(
@original_request.scheme,
@original_request.authority,
@original_request.method,
@original_request.path,
@original_request.version,
@original_request.headers,
@request_body,
@original_request.protocol
)
# Create final response with buffered body:
final_response = nil
if @original_response
final_response = ::Protocol::HTTP::Response.new(
@original_response.version,
@original_response.status,
@original_response.headers,
@response_body,
@original_response.protocol
)
end
# Create and record the interaction:
interaction_data = {}
interaction_data[:error] = @error if @error
# Add as_json data for debugging (captured at completion time):
interaction_data[:debug] = {}
interaction_data[:debug][:request_body] = @debug_request_body if @debug_request_body
interaction_data[:debug][:response_body] = @debug_response_body if @debug_response_body
interaction = Interaction.new(
interaction_data,
request: final_request,
response: final_response
)
@store.call(interaction)
end