Async::HTTP::CaptureSourceAsyncHTTPCaptureInteractionTracker

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