Class: ReactOnRailsPro::RendererHttpClient
- Inherits:
-
Object
- Object
- ReactOnRailsPro::RendererHttpClient
show all
- Defined in:
- lib/react_on_rails_pro/renderer_http_client.rb,
sig/react_on_rails_pro/renderer_http_client.rbs
Overview
rubocop:disable Metrics/ClassLength
Defined Under Namespace
Classes: BufferedResponseBody, ConnectTimeoutWrapper, ConnectionError, Error, HTTPError, MultipartBody, MultipartFileBody, PersistentThreadClient, Response, TimeoutError
Constant Summary
collapse
- CONNECTION_ERRORS =
[
SocketError,
IOError,
Errno::ECONNRESET,
Errno::ECONNREFUSED,
Errno::EHOSTUNREACH,
Errno::ENETUNREACH,
Errno::EPIPE,
Errno::ETIMEDOUT,
Protocol::HTTP::RefusedError,
Protocol::HTTP2::StreamError
].freeze
- SCHEDULER_CLIENTS_KEY =
Per-scheduler storage for persistent HTTP clients. When an outer Fiber.scheduler
exists BEFORE we enter Sync {}, clients are stored on the scheduler object using
this instance variable key. This enables connection reuse across requests within
the same long-lived scheduler context (e.g., Falcon, Puma with async scheduler).
The hash maps origin URLs to Async::HTTP::Client instances.
IMPORTANT: We only use persistent mode when a scheduler already exists before
execute_request enters Sync {}. If Sync {} creates an ephemeral scheduler,
we use the ephemeral client path to ensure proper cleanup when the block exits.
:@__ror_pro_http_clients__
- CLIENT_GENERATION_MUTEX =
Mutex.new
Class Method Summary
collapse
Instance Method Summary
collapse
Constructor Details
#initialize(origin:, pool_size:, connect_timeout:, read_timeout:, force_http2: true) ⇒ RendererHttpClient
Returns a new instance of RendererHttpClient.
563
564
565
566
567
568
569
570
571
572
573
|
# File 'lib/react_on_rails_pro/renderer_http_client.rb', line 563
def initialize(origin:, pool_size:, connect_timeout:, read_timeout:, force_http2: true)
@origin = origin
@pool_size = pool_size
@connect_timeout = connect_timeout
@read_timeout = read_timeout
@force_h2c = force_http2 && URI.parse(origin).scheme == "http"
@thread_clients = {}.compare_by_identity
@thread_clients_mutex = Mutex.new
@closed = false
@closed_mutex = Mutex.new
end
|
Class Method Details
.build_form_body(form) ⇒ [Array[[String, String]], MultipartBody | String]
489
490
491
492
493
494
495
496
|
# File 'lib/react_on_rails_pro/renderer_http_client.rb', line 489
def build_form_body(form)
return build_multipart_body(form) if form.any? { |_name, value| file_part?(value) }
[
[["content-type", "application/x-www-form-urlencoded"]],
URI.encode_www_form(flatten_url_encoded_form(form))
]
end
|
.build_multipart_body(form, boundary: SecureRandom.hex(24)) ⇒ Object
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
|
# File 'lib/react_on_rails_pro/renderer_http_client.rb', line 472
def build_multipart_body(form, boundary: SecureRandom.hex(24))
raise ArgumentError, "boundary must not contain '--'" if boundary.include?("--")
body = MultipartBody.new
form.each do |name, value|
append_multipart_value(body, boundary, name, value)
end
body << "--#{boundary}--\r\n"
[
[["content-type", "multipart/form-data; boundary=#{boundary}"]],
body
]
end
|
.bump_client_generation ⇒ Integer
466
467
468
469
470
|
# File 'lib/react_on_rails_pro/renderer_http_client.rb', line 466
def bump_client_generation
CLIENT_GENERATION_MUTEX.synchronize do
@client_generation = (@client_generation || 0) + 1
end
end
|
.client_generation ⇒ Integer
460
461
462
463
464
|
# File 'lib/react_on_rails_pro/renderer_http_client.rb', line 460
def client_generation
CLIENT_GENERATION_MUTEX.synchronize do
@client_generation ||= 0
end
end
|
.get(url, connect_timeout:, read_timeout:) ⇒ Response
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
|
# File 'lib/react_on_rails_pro/renderer_http_client.rb', line 435
def get(url, connect_timeout:, read_timeout:)
origin, path = split_url(url)
client = new(
origin:,
pool_size: 1,
connect_timeout:,
read_timeout:,
force_http2: false
)
response = client.get(path)
response.body
response
ensure
client&.close
end
|
.split_url(url) ⇒ [String, String]
452
453
454
455
456
457
458
|
# File 'lib/react_on_rails_pro/renderer_http_client.rb', line 452
def split_url(url)
uri = URI.parse(url)
port = uri.port unless uri.default_port == uri.port
origin = "#{uri.scheme}://#{uri.host}#{":#{port}" if port}"
[origin, uri.request_uri]
end
|
Instance Method Details
#close ⇒ nil
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
|
# File 'lib/react_on_rails_pro/renderer_http_client.rb', line 611
def close
return unless mark_closed
close_error = nil
scheduler = Fiber.scheduler
begin
evict_client_from_scheduler(scheduler) if scheduler
rescue StandardError => e
close_error ||= e
end
begin
close_thread_clients
rescue StandardError => e
close_error ||= e
end
raise close_error if close_error
end
|
585
586
587
588
589
590
591
592
|
# File 'lib/react_on_rails_pro/renderer_http_client.rb', line 585
def get(path)
ensure_open!
build_response(stream: false) do |yielder, status_assigner, |
execute_request(:get, path, [[], nil],
stream: false,
response_handlers: [yielder, status_assigner, ])
end
end
|
#post(path, form: nil, json: nil, stream: false) ⇒ Object
575
576
577
578
579
580
581
582
583
|
# File 'lib/react_on_rails_pro/renderer_http_client.rb', line 575
def post(path, form: nil, json: nil, stream: false)
ensure_open!
, body = request_body(form:, json:)
build_response(stream:) do |yielder, status_assigner, |
execute_request(:post, path, [, body],
stream:,
response_handlers: [yielder, status_assigner, ])
end
end
|
#post_bidi(path, headers:) ⇒ [untyped, Response]
Bidirectional HTTP/2 streaming POST. Returns [output, response] where:
- output is a Protocol::HTTP::Body::Writable::Output (supports << and close)
- response is a lazy Response whose body is consumed via Response#each
The caller writes NDJSON lines to output while concurrently reading response
chunks. Calling output.close sends END_STREAM on the HTTP/2 stream.
600
601
602
603
604
605
606
607
608
609
|
# File 'lib/react_on_rails_pro/renderer_http_client.rb', line 600
def post_bidi(path, headers:)
ensure_open!
writable = Protocol::HTTP::Body::Writable.new
response = build_response(stream: true) do |yielder, status_assigner, |
execute_request(:post, path, [, writable],
stream: true,
response_handlers: [yielder, status_assigner, ])
end
[writable.output, response]
end
|