@@ -328,82 +328,108 @@ func (server *relayMinerHTTPServer) serveSyncRequest(
328328 // Capture the service call request duration metric.
329329 relayer .CaptureServiceDuration (serviceId , serviceCallStartTime , httpResponse .StatusCode )
330330
331- // Serialize the service response to be sent back to the client.
332- // This will include the status code, headers, and body.
333- wrappedHTTPResponse , responseBz , err := SerializeHTTPResponse (logger , httpResponse , server .serverConfig .MaxBodySize )
334- if err != nil {
335- logger .Error ().Err (err ).Msg ("❌ Failed serializing the service response" )
336- return relayRequest , err
337- }
338- // Early close backend response body to free up pool resources.
339- CloseBody (logger , httpResponse .Body )
340-
341- // Pass through all backend responses including errors.
342- // Allows clients to see real HTTP status codes from backend service.
343- // Log non-2XX status codes for monitoring but don't block response.
344- if httpResponse .StatusCode >= http .StatusMultipleChoices {
345- logger .Error ().
346- Int ("status_code" , httpResponse .StatusCode ).
347- Str ("request_url" , httpRequestWithUpdatedTimeout .URL .String ()).
348- Str ("request_payload_first_bytes" , polylog .Preview (string (relayRequest .Payload ))).
349- Str ("response_payload_first_bytes" , polylog .Preview (string (wrappedHTTPResponse .BodyBz ))).
350- Msg ("backend service returned a non-2XX status code. Passing it through to the client." )
331+ // Check if the response is a stream
332+ streamThis := IsStreamingResponse (httpResponse )
333+
334+ // Create empty relay response
335+ relayResponse := & types.RelayResponse {
336+ Meta : types.RelayResponseMetadata {SessionHeader : meta .SessionHeader },
337+ Payload : nil ,
351338 }
352339
353- logger . Debug ().
354- Str ( "relay_request_session_header" , meta . SessionHeader . String ()).
355- Msg ("building relay response protobuf from service response " )
340+ var responseSize float64
341+ if streamThis {
342+ logger . Debug (). Msg ("Handling streaming request. " )
356343
357- // Check context cancellation before building relay response to prevent signature race conditions
358- if ctxErr := ctxWithDeadline .Err (); ctxErr != nil {
359- logger .Warn ().Err (ctxErr ).Msg ("⚠️ Context canceled before building relay response - preventing signature race condition" )
360- return relayRequest , ErrRelayerProxyTimeout .Wrapf (
361- "request context canceled during response building: %v" ,
362- ctxErr ,
363- )
364- }
344+ // Process and assign the relay response
345+ relayResponse , responseSize , err = server .HandleHttpStream (httpResponse , writer , meta , logger )
346+ if err != nil {
347+ return relayRequest , err
348+ }
365349
366- // Build the relay response using the original service's response.
367- // Use relayRequest.Meta.SessionHeader on the relayResponse session header since it
368- // was verified to be valid and has to be the same as the relayResponse session header.
369- relayResponse , err := server .newRelayResponse (responseBz , meta .SessionHeader , supplierOperatorAddress )
370- if err != nil {
371- logger .Error ().Err (err ).Msg ("❌ Failed building the relay response" )
372- // The client should not have knowledge about the RelayMiner's issues with
373- // building the relay response. Reply with an internal error so that the
374- // original error is not exposed to the client.
375- return relayRequest , ErrRelayerProxyInternalError .Wrap (err .Error ())
376- }
350+ } else {
351+ logger .Debug ().Msg ("Handling normal request." )
377352
378- relay := & types.Relay {Req : relayRequest , Res : relayResponse }
353+ // Serialize the service response to be sent back to the client.
354+ // This will include the status code, headers, and body.
355+ wrappedHTTPResponse , responseBz , err := SerializeHTTPResponse (logger , httpResponse , server .serverConfig .MaxBodySize )
356+ if err != nil {
357+ logger .Error ().Err (err ).Msg ("❌ Failed serializing the service response" )
358+ return relayRequest , err
359+ }
379360
380- // Capture the time after response time for the relay.
381- responsePreparationEnd := time .Now ()
382- // Add response preparation duration to the logger such that any log before errors will have
383- // as much request duration information as possible.
384- logger = logger .With (
385- "response_preparation_duration" ,
386- time .Since (backendServiceProcessingEnd ).String (),
387- )
388- relayer .CaptureResponsePreparationDuration (serviceId , backendServiceProcessingEnd )
361+ // Pass through all backend responses including errors.
362+ // Allows clients to see real HTTP status codes from backend service.
363+ // Log non-2XX status codes for monitoring but don't block response.
364+ if httpResponse .StatusCode >= http .StatusMultipleChoices {
365+ logger .Error ().
366+ Int ("status_code" , httpResponse .StatusCode ).
367+ Str ("request_url" , httpRequest .URL .String ()).
368+ Str ("request_payload_first_bytes" , polylog .Preview (string (relayRequest .Payload ))).
369+ Str ("response_payload_first_bytes" , polylog .Preview (string (wrappedHTTPResponse .BodyBz ))).
370+ Msg ("backend service returned a non-2XX status code. Passing it through to the client." )
371+ }
372+
373+ logger .Debug ().
374+ Str ("relay_request_session_header" , meta .SessionHeader .String ()).
375+ Msg ("building relay response protobuf from service response" )
376+
377+ // Check context cancellation before building relay response to prevent signature race conditions
378+ if ctxErr := ctxWithDeadline .Err (); ctxErr != nil {
379+ logger .Warn ().Err (ctxErr ).Msg ("⚠️ Context canceled before building relay response - preventing signature race condition" )
380+ return relayRequest , ErrRelayerProxyTimeout .Wrapf (
381+ "request context canceled during response building: %v" ,
382+ ctxErr ,
383+ )
384+ }
385+
386+ // Build the relay response using the original service's response.
387+ // Use relayRequest.Meta.SessionHeader on the relayResponse session header since it
388+ // was verified to be valid and has to be the same as the relayResponse session header.
389+ relayResponse , err = server .newRelayResponse (responseBz , meta .SessionHeader , meta .SupplierOperatorAddress )
390+ if err != nil {
391+ logger .Error ().Err (err ).Msg ("❌ Failed building the relay response" )
392+ // The client should not have knowledge about the RelayMiner's issues with
393+ // building the relay response. Reply with an internal error so that the
394+ // original error is not exposed to the client.
395+ return relayRequest , ErrRelayerProxyInternalError .Wrap (err .Error ())
396+ }
397+
398+ // Capture the time after response time for the relay.
399+ responsePreparationEnd := time .Now ()
400+ // Add response preparation duration to the logger such that any log before errors will have
401+ // as much request duration information as possible.
402+ logger = logger .With (
403+ "response_preparation_duration" ,
404+ time .Since (backendServiceProcessingEnd ).String (),
405+ )
406+ relayer .CaptureResponsePreparationDuration (serviceId , backendServiceProcessingEnd )
407+
408+ // Send the relay response to the client.
409+ err = server .sendRelayResponse (relayResponse , writer )
410+ logger = logger .With ("send_response_duration" , time .Since (responsePreparationEnd ).String ())
411+ if err != nil {
412+ // If the originHost cannot be parsed, reply with an internal error so that
413+ // the original error is not exposed to the client.
414+ clientError := ErrRelayerProxyInternalError .Wrap (err .Error ())
415+ // Log current time to highlight writer i/o timeout errors.
416+ logger .Warn ().Err (err ).Time ("current_time" , time .Now ()).Msg ("❌ Failed sending relay response" )
417+ return relayRequest , clientError
418+ }
419+
420+ // Set response size
421+ responseSize = float64 (relayResponse .Size ())
389422
390- // Send the relay response to the client.
391- err = server .sendRelayResponse (relay .Res , writer )
392- logger = logger .With ("send_response_duration" , time .Since (responsePreparationEnd ).String ())
393- if err != nil {
394- // If the originHost cannot be parsed, reply with an internal error so that
395- // the original error is not exposed to the client.
396- clientError := ErrRelayerProxyInternalError .Wrap (err .Error ())
397- // Log current time to highlight writer i/o timeout errors.
398- logger .Warn ().Err (err ).Time ("current_time" , time .Now ()).Msg ("❌ Failed sending relay response" )
399- return relayRequest , clientError
400423 }
401424
425+ // Create the relay response
426+ relay := & types.Relay {Req : relayRequest , Res : relayResponse }
427+
402428 logger .ProbabilisticDebugInfo (polylog .ProbabilisticDebugInfoProb ).Msg ("relay request served successfully" )
403429
404430 relayer .RelaysSuccessTotal .With ("service_id" , serviceId ).Add (1 )
405431
406- relayer .RelayResponseSizeBytes .With ("service_id" , serviceId ).Observe (float64 ( relay . Res . Size ()) )
432+ relayer .RelayResponseSizeBytes .With ("service_id" , serviceId ).Observe (responseSize )
407433
408434 // Verify relay reward eligibility a SECOND time AFTER completing backend request.
409435 //
0 commit comments