Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The Less-Told Story of Socket Timeouts

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.

The Less-Told Story of Socket Timeouts

More Decks by Misaki Shioi(塩井美咲/しおい)

Other Decks in Programming

Transcript

  1. "SHVNFOUTGPSVTFSTQFDJ fi FEUJNFPVU 8IFOBOZPGUIFTFJTTFU JGUIFUBSHFUPQFSBUJPOEPFTOPU DPNQMFUFXJUIJOUIFTQFDJ fi FEUJNF 4PDLFUUDQ 5$14PDLFUOFX

    4FSWFS %/4TFSWFS Socket.tcp("ruby-lang.org", 80, open_timeout: 1) "UUFNQUUPDPOOFDU PQFO@UJNFPVU 3FTPMWFUIFIPTUOBNF
  2. 5IJTJTTVFQPJOUFEPVUUIBUOPOCMPDLJOHDPOOFDUJPODPEF XJUIBUJNFPVUUFOETUPCFWFSCPTF BTTIPXOJOUIJTTBNQMF The current construct for doing a non-blocking

    connect with timeout is too verbose: addr = Socket.pack_sockaddr_in(9418, "127.0.0.1") s = Socket.new(:AF_INET, :SOCK_STREAM, 0) begin s.connect_nonblock(addr) rescue Errno::EINPROGRESS IO.select(nil, [s], nil, 0.5) or raise Timeout::Error end 4UBSUBOPOCMPDLJOHDPOOFDUJPO 5JNFPVUJOTFD GSPNOPSNBMQFSTPO &SJD8POH IUUQTCVHTSVCZMBOHPSHJTTVFT "UJNFPVUGPSDPOOFDUJPOBUUFNQUT
  3. 5IFQSPQPTBMXBTUPBEEBDPOOFDU@UJNFPVU LFZXPSEBSHVNFOUUP5$14PDLFUOFXTPUIBU DPOOFDUJPOBUUFNQUTDPVMECFUJNFEPVU Proposed API would be: TCPSocket.new(remote_host, remote_port,
 connect_timeout:

    0.5, local_host: nil, local_port: nil) Or: TCPSocket.new(remote_host, remote_port, connect_timeout: 0.5) GSPNOPSNBMQFSTPO &SJD8POH IUUQTCVHTSVCZMBOHPSHJTTVFT "UJNFPVUGPSDPOOFDUJPOBUUFNQUT
  4. 8IZPOMZUIFDPOOFDUJPOXBTTVCKFDUUPUIFUJNFPVU  BOEOPUOBNFSFTPMVUJPO  Proposed API would be: TCPSocket.new(remote_host, remote_port,


    connect_timeout: 0.5, local_host: nil, local_port: nil) Or: TCPSocket.new(remote_host, remote_port, connect_timeout: 0.5) GSPNOPSNBMQFSTPO &SJD8POH IUUQTCVHTSVCZMBOHPSHJTTVFT "UJNFPVUGPSDPOOFDUJPOBUUFNQUT
  5. "UJNFPVUGPSOBNFSFTPMVUJPOJOSFTPMW 5IJTJTTVFQSPQPTFEBEEJOHTVQQPSUGPS OBNFSFTPMVUJPOUJNFPVUTUPUIFSFTPMWMJCSBSZ ※ The resolv library is a standard

    library for performing DNS-based name resolution. GSPNOPSNBMQFSTPO &SJD8POH IUUQTCVHTSVCZMBOHPSHJTTVFT
  6. -BZFSFE5JNFPVU%FTJHO 0CUBJOUIFEFTUJOBUJPO*1BEESFTTFTVTJOH UIFSFTPMWMJCSBSZ require "resolv" dns = Resolv::DNS.new dns.timeouts =

    1 dns.getaddress("example.com") $MJFOU %/4TFSWFS 3FTPMWFUIFIPTUOBNFXJUISFTPMW 4FSWFS "OBNFSFTPMVUJPOUJNFPVU
  7. 0UIFSUPQJD8IBUJGBIPTUIBTNVMUJQMF*1BEESFTTFT *OJOUSPEVDJOHDPOOFDUJPOUJNFPVUT  UIFSFXBTBMTPEJTDVTTJPOBCPVUIPXJUTIPVMECFIBWF XIFOBIPTUIBTNVMUJQMF*1BEESFTTFT I remember multiple IP addresses

    issue. The behavior of timeout is not clear if two or more IP addresses are given for a hostname. GSPNBLS "LJSB5BOBLB IUUQTCVHTSVCZMBOHPSHJTTVFTOPUF
  8. "OPUIFSQPJOUJTUIBUUIJTGFBUVSFXBTPSJHJOBMMZQSPQPTFE GPS5$14PDLFUOFX 0UIFSUPQJD8IJDIDMBTTTIPVMEUIJTCFJOUSPEVDFEJOUP Proposed API would be: TCPSocket.new(remote_host, remote_port,
 connect_timeout:

    0.5, local_host: nil, local_port: nil) Or: TCPSocket.new(remote_host, remote_port, connect_timeout: 0.5) GSPNOPSNBMQFSTPO &SJD8POH IUUQTCVHTSVCZMBOHPSHJTTVFT
  9. 4JODFTVDI fl FYJCMFDPO fi HVSBUJPOXBTDPOTJEFSFENPSF BQQSPQSJBUFGPSUIFMPXFSMFWFM4PDLFUDMBTT  UIFGVODUJPOBMJUZXBTVMUJNBUFMZBEEFEUP4PDLFUUDQ 0UIFSUPQJD8IJDIDMBTTTIPVMEUIJTCFJOUSPEVDFEJOUP How

    about Socket class? You can implement timeout on Socket. I think you need full power of socket API, so you should use low level bindings for socket API i.e. Socket class. GSPNBLS "LJSB5BOBLB IUUQTCVHTSVCZMBOHPSHJTTVFTOPUF
  10. 0OFVOEFSMZJOHDPODFSOXBTUIBUMJCSBSJFTTVDIBT OFUIUUQSFMJFEPOUIFUJNFPVUMJCSBSZUPNBOBHFUJNFPVUT Currently, we use Timeout in Net::HTTP and other

    standard libraries. lib/net/http.rb 945 s = Timeout.timeout(@open_timeout, Net::OpenTimeout) { 946 begin 947 TCPSocket.open(conn_address, conn_port, @local_host, @local_port) 948 rescue => e 949 raise e, "Failed to open TCP connection to " + 950 "#{conn_address}:#{conn_port} (#{e.message})" 951 end 952 } GSPN(MBTT@TBHB .BTBLJ.BUTVTIJUB IUUQTCVHTSVCZMBOHPSHJTTVFT #BDLHSPVOE5JNFPVU)BOEMJOHJOOFUIUUQ 5IFUJNFPVUMJCSBSZTNFUIPE
  11. GSPN(MBTT@TBHB .BTBLJ.BUTVTIJUB IUUQTCVHTSVCZMBOHPSHJTTVFT ※ The timeout library is a standard

    library that forces an operation to be interrupted by raising an exception once a speci fi ed time has elapsed. Currently, we use Timeout in Net::HTTP and other standard libraries. lib/net/http.rb 945 s = Timeout.timeout(@open_timeout, Net::OpenTimeout) { 946 begin 947 TCPSocket.open(conn_address, conn_port, @local_host, @local_port) 948 rescue => e 949 raise e, "Failed to open TCP connection to " + 950 "#{conn_address}:#{conn_port} (#{e.message})" 951 end 952 } 5IFUJNFPVUMJCSBSZTNFUIPE #BDLHSPVOE5JNFPVU)BOEMJOHJOOFUIUUQ
  12. OFUIUUQVTFEUIFUJNFPVUMJCSBSZUPUPXBJUGPSUIFPWFSBMM PQFSBUJPO GSPNOBNFSFTPMVUJPOUPDPOOFDUJPOFTUBCMJTINFOU Currently, we use Timeout in Net::HTTP and

    other standard libraries. lib/net/http.rb 945 s = Timeout.timeout(@open_timeout, Net::OpenTimeout) { 946 begin 947 TCPSocket.open(conn_address, conn_port, @local_host, @local_port) 948 rescue => e 949 raise e, "Failed to open TCP connection to " + 950 "#{conn_address}:#{conn_port} (#{e.message})" 951 end 952 } GSPN(MBTT@TBHB .BTBLJ.BUTVTIJUB IUUQTCVHTSVCZMBOHPSHJTTVFT 5IFPWFSBMMUJNF #BDLHSPVOE5JNFPVU)BOEMJOHJOOFUIUUQ
  13. 8IJMFHFUBEESJOGP  JTCMPDLJOH JUDBOOPUCFJOUFSSVQUFE CZBUJNFPVU BOEFWFO$USM $IBTOPF ff FDU 5IJTIBECFFOBOJTTVFTJODFCFGPSF3VCZ

    $MJFOU %/4TFSWFS *UDBOUUJNFPVU $USM $IBTOPF ff FDU )PXUPJOUFSSVQUUIFOBNFSFTPMVUJPOJOQSPHSFTT HFUBEESJOGP   8BJUJOHGPS%/4SFTQPOTF 4FOE%/4RVFSZ
  14. "TBTPMVUJPOUPUIJTQSPCMFN  UIJTJTTVFQSPQPTFESFQMBDJOHHFUBEESJOGP   XJUIHFUBEESJOGP@B   It uses

    getaddrinfo_a(3) if available, otherwise it uses Timeout. We can avoid thread creation to make a TCP connection if getaddrinfo_a(3) is available. GSPN(MBTT@TBHB .BTBLJ.BUTVTIJUB IUUQTCVHTSVCZMBOHPSHJTTVFT )PXUPJOUFSSVQUUIFOBNFSFTPMVUJPOJOQSPHSFTT
  15. HFUBEESJOGP@B  TVQQPSUTBNPEF JOXIJDIHFUBEESJOGP  JTDBSSJFEPVU CZBCBDLHSPVOEXPSLFSUISFBE HFUBEESJOGP@B  8PSLFS

    %/44FSWFS 1SFQBSF .BJO HFUBEESJOGP   8IBUJTHFUBEESJOGP@B  3FTPMWFUIFIPTUOBNF
  16. $IBOHFTJOUSPEVDFECZUIJTJTTVF 5IJTQSPQPTBMSFQMBDFETPNFVTFTPGHFUBEESJOGP   JOUIFDPEFXJUIHFUBEESJOGP@B  BOEBMTPJNQMFNFOUFE OBNFSFTPMVUJPOUJNFPVUTVQQPSU GSPN(MBTT@TBHB .BTBLJ.BUTVTIJUB

    IUUQTCVHTSVCZMBOHPSHJTTVFT Socket.tcp supports connect_timeout, but Addrinfo.getaddrinfo doesn't support timeout. We need to use Timeout to wait name resolution. In this patch, Addrinfo.getaddrinfo support timeout and Socket.tcp accepts resolv_timeout. It uses getaddrinfo_a(3) if available, otherwise it uses Timeout. We can avoid thread creation to make a TCP connection if getaddrinfo_a(3) is available. ˞IUUQTHJUIVCDPNSVCZSVCZDPNNJUGDDBDFCDEBEB
  17. $IBOHFTJOUSPEVDFECZUIJTJTTVF "TUIF"1*TGPSUIJT  BUJNFPVULFZXPSEBSHVNFOUXBTBEEFEUP"EESJOGPHFUBEESJOGP  BOEBSFTPMW@UJNFPVULFZXPSEBSHVNFOUXBTBEEFEUP4PDLFUUDQ GSPN(MBTT@TBHB .BTBLJ.BUTVTIJUB IUUQTCVHTSVCZMBOHPSHJTTVFT Socket.tcp

    supports connect_timeout, but Addrinfo.getaddrinfo doesn't support timeout. We need to use Timeout to wait name resolution. In this patch, Addrinfo.getaddrinfo support timeout and Socket.tcp accepts resolv_timeout. It uses getaddrinfo_a(3) if available, otherwise it uses Timeout. We can avoid thread creation to make a TCP connection if getaddrinfo_a(3) is available.
  18. 4PDLFUHFUBEESJOGPJT MJLF"EESJOGPHFUBEESJOGP  BNFUIPEGPSQFSGPSNJOHOBNFSFTPMVUJPO *UIBOEMFTMPXFSMFWFMJOGPSNBUJPOUIBO"EESJOGPHFUBEESJOGP .BLF4PDLFUHFUBEESJOGPJOUFSSVQUJCMF require "socket" Addrinfo.getaddrinfo("www.ruby-lang.org", 80)

    => [#<Addrinfo: [****:****:****::***]:80 TCP (www.ruby-lang.org)>, ...] Socket.getaddrinfo("www.ruby-lang.org", 80) => [["AF_INET6", 80, "****:****:****::***", "****:****:****::***", 30, 1, 6], ...]
  19. "SFQSPEVDFSXBTBMTPSFQPSUFE*UBQQFBSFEUIBUJG  4PDLFUHFUBEESJOGPXBTDBMMFE UIFO  GPSL XBTQFSGPSNFE  BOE 

    4PDLFUHFUBEESJOGPXBTDBMMFEBHBJOJOUIFDIJMEQSPDFTT Here's a small script that reproduces the problem: require "socket" Socket.getaddrinfo("localhost", nil) pid = fork do Socket.getaddrinfo("localhost", nil) end Process.wait pid   GSPNFVHFOFJVT &VHFOF,FOOZ IUUQTCVHTSVCZMBOHPSHJTTVFTOPUF  3BJMT"DUJWF+PCJOUFHSBUJPOUFTUTGBJMFT
  20. UIFDBMMXPVMEIBOHBOEOFWFSSFUVSO 8IBUFYBDUMZXBTIBQQFOJOH Here's a small script that reproduces the problem:

    require "socket" Socket.getaddrinfo("localhost", nil) pid = fork do Socket.getaddrinfo("localhost", nil) end Process.wait pid GSPNFVHFOFJVT &VHFOF,FOOZ IUUQTCVHTSVCZMBOHPSHJTTVFTOPUF )BOHT 3BJMT"DUJWF+PCJOUFHSBUJPOUFTUTGBJMFT
  21. 1SPDFTT "OEBGUFS fi OJTIJOHBSFRVFTU UIFZSFNBJOBMJWFGPS BDFSUBJOQFSJPEPGUJNF XBJUJOHGPSUIFOFYUSFRVFTU HFUBEESJOGP@B  

    3FTVNFUIFQSPDFTTJOH *GOPOFXSFRVFTUTBSSJWFXJUIJOUIBUQFSJPE  UIFZUFSNJOBUF 8PSLFS .BJO 8IBUXBTIBQQFOJOHXJUIHFUBEESJOGP@B 
  22. 8IFOHFUBEESJOGP@B  JTDBMMFEBHBJOJOUIFDIJME QSPDFTT UIFTZODISPOJ[BUJPOTUBUFCFDPNFT JODPOTJTUFOU BOEUIFQSPDFTTIBOHT $IJMEQSPDFTT HFUBEESJOGP@B 

     )BOHT 5IFJOUFSOBMTUBUF 8PSLFSUISFBETBSFXBJUJOH /PXPSLFSUISFBET $PQJFE 8IBUXBTIBQQFOJOHXJUIHFUBEESJOGP@B 
  23. 4PMWJOHUIFCMPDLJOHJTTVFJOOBNFSFTPMVUJPO 5PBEESFTTUIJTQSPCMFN  BNFUIPEXBTQSPQPTFEUIBUDPNCJOFTHFUBEESJOGP   XJUIQUISFBE I wrote a

    patch to make getaddrinfo(3) work in a separate pthread. https://github.com/ruby/ruby/pull/8695 GSPNNBNF :VTVLF&OEPI IUUQTCVHTSVCZMBOHPSHJTTVFT
  24. 4PMWJOHUIFCMPDLJOHJTTVFJOOBNFSFTPMVUJPO "EESJOGPHFUBEESJOGP  ➡︎ BEESJOGP@T@HFUBEESJOGP ɹ ➡︎ BEESJOGP@MJTU@OFX ɹ ➡︎

    DBMM@HFUBEESJOGP ɹɹ ➡︎ STPDL@HFUBEESJOGP 5IJTDIBOHFXBTJNQMFNFOUFEJO STPDL@HFUBEESJOGP XIJDIJTDBMMFEJOUFSOBMMZ CZ"EESJOGPHFUBEESJOGP 5IJTDIBOHFXBTJOUSPEVDFE
  25. 4PMWJOHUIFCMPDLJOHJTTVFJOOBNFSFTPMVUJPO "EESJOGPHFUBEESJOGP  ➡︎ BEESJOGP@T@HFUBEESJOGP ɹ ➡︎ BEESJOGP@MJTU@OFX ɹ ➡︎

    DBMM@HFUBEESJOGP ɹɹ ➡︎ STPDL@HFUBEESJOGP "TBSFTVMU OBNFSFTPMVUJPOOPMPOHFSCMPDLTJOBMM NFUIPETUIBUVTFSTPDL@HFUBEESJOGP  JODMVEJOH4PDLFUHFUBEESJOGP 4PDLFUHFUBEESJOGP  ➡︎ TPDL@T@HFUBEESJOGP ɹ ➡︎ STPDL@HFUBEESJOGP 5IJTDIBOHFXBTJOUSPEVDFE
  26. )&WQSJPSJUJ[FTDPOOFDUJPOTPWFS*1W *GUIF*1WBEESFTTFTBSFSFTPMWFE fi STU XBJUVQUPNTGPSUIF *1WSFTPMVUJPOUPDPNQMFUFCFGPSFTUBSUJOHBDPOOFDUJPOBUUFNQU )PX)&WXPSLT %/4TFSWFS 4PDLFUUDQ 5$14PDLFUOFX

    4FSWFS 4FOE%/4RVFSZGPS*1W 4FOE%/4RVFSZGPS*1W 3FUVSO*1W%/4SFTQPOTF fi STU 8BJUJOHGPSUIF*1W%/4SFTQPOTF 8BJUVQUPNTCFGPSF*1WDPOOFDUJPO
  27. 3FTPMVUJPO%FBMBZ$POOFDUJPO"UUFNQU%FMBZ def self.tcp_with_fast_fallback( host, port, ..., connect_timeout: nil, resolv_timeout: nil

    ) # ... resolution_delay_expires_at = nil connection_attempt_delay_expires_at = nil # ... end *OUIFJNQMFNFOUBUJPO UIFTFEFMBZTBSFUSBDLFEVTJOH UIFWBSJBCMFTSFTPMVUJPO@EFMBZ@FYQJSFT@BUBOE DPOOFDUJPO@BUUFNQU@EFMBZ@FYQJSFT@BU 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC
  28. 3FTPMVUJPO%FBMBZ$POOFDUJPO"UUFNQU%FMBZ def self.tcp_with_fast_fallback( host, port, ..., connect_timeout: nil, resolv_timeout: nil

    ) # ... resolution_delay_expires_at = nil connection_attempt_delay_expires_at = nil # ... end #PUIBSFJOJUJBMJ[FEUPOJMBUUIFTUBSUPGUIFNFUIPE 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC
  29. SFTPMW@UJNFPVUDPOOFDU@UJNFPVU *ODPOUSBTU SFTPMW@UJNFPVUBOEDPOOFDU@UJNFPVUXBJU VQUPBVTFSTQFDJ fi FEUJNFPVU %/4TFSWFS 4PDLFUUDQ 5$14PDLFUOFX 4FSWFS

    SFTPMW@UJNFPVU *GUIFUJNFPVUFYQJSFT  UIFXBJUJTUFSNJOBUFEBOEBOFSSPSJTSBJTFE "UUFNQUUPDPOOFDU 3FTPMWFUIFIPTUOBNF DPOOFDU@UJNFPVU
  30. def self.tcp_with_fast_fallback( host, port, ..., connect_timeout: nil, resolv_timeout: nil )

    # ... resolution_delay_expires_at = nil connection_attempt_delay_expires_at = nil user_specified_connect_timeout_at = nil # ... user_specified_resolv_timeout_at = resolv_timeout ? now + resolv_timeout : Float::INFINITY # ... end 5IFTFUJNFPVUTBSFUSBDLFEVTJOHUIFWBSJBCMFT VTFS@TQFDJ fi FE@SFTPMW@UJNFPVU@BUBOE VTFS@TQFDJ fi FE@DPOOFDU@UJNFPVU@BU SFTPMW@UJNFPVUDPOOFDU@UJNFPVU 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC
  31. def self.tcp_with_fast_fallback( host, port, ..., connect_timeout: nil, resolv_timeout: nil )

    # ... resolution_delay_expires_at = nil connection_attempt_delay_expires_at = nil user_specified_connect_timeout_at = nil # ... user_specified_resolv_timeout_at = resolv_timeout ? now + resolv_timeout : Float::INFINITY # ... end VTFS@TQFDJ fi FE@DPOOFDU@UJNFPVU@BUJTJOJUJBMJ[FE UPOJMBUUIFTUBSUPGUIFNFUIPE SFTPMW@UJNFPVUDPOOFDU@UJNFPVU 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC
  32. def self.tcp_with_fast_fallback( host, port, ..., connect_timeout: nil, resolv_timeout: nil )

    # ... resolution_delay_expires_at = nil connection_attempt_delay_expires_at = nil user_specified_connect_timeout_at = nil # ... user_specified_resolv_timeout_at = resolv_timeout ? now + resolv_timeout : Float::INFINITY # ... end *GSFTPMW@UJNFPVUJTTQFDJ fi FE  VTFS@TQFDJ fi FE@SFTPMW@UJNFPVU@BUJTTFUUP JUTFYQJSBUJPOUJNF SFTPMW@UJNFPVUDPOOFDU@UJNFPVU 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC 5IFVTFSTQFDJ fi FEFYQJSBUJPOUJNF
  33. def self.tcp_with_fast_fallback( host, port, ..., connect_timeout: nil, resolv_timeout: nil )

    # ... resolution_delay_expires_at = nil connection_attempt_delay_expires_at = nil user_specified_connect_timeout_at = nil # ... user_specified_resolv_timeout_at = resolv_timeout ? now + resolv_timeout : Float::INFINITY # ... end 0UIFSXJTF JUJTTFUUP'MPBU*/'*/*5: UPNFBOXBJUJOEF fi OJUFMZ SFTPMW@UJNFPVUDPOOFDU@UJNFPVU 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC NFBOTJOEF fi OJUFMZ
  34. %FUFSNJOJOHUIFOBNFSFTPMVUJPOUJNFPVU ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at || connection_attempt_delay_expires_at else [

    user_specified_resolv_timeout_at, user_specified_connect_timeout_at ].compact.max end 5IFFYQJSBUJPOUJNFJTEFUFSNJOFECZ UIFSFUVSOWBMVFPGUIJTDPOEJUJPOBMCSBODI 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC
  35. %FUFSNJOJOHUIFOBNFSFTPMVUJPOUJNFPVU ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at || connection_attempt_delay_expires_at else [

    user_specified_resolv_timeout_at, user_specified_connect_timeout_at ].compact.max end 5IFDPOEJUJPOJTXIFUIFSBOZ DBOEJEBUFEFTUJOBUJPOBEESFTTFTBSFBWBJMBCMF "OZDBOEJEBUFEFTUJOBUJPOBEESFTTFT  'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC
  36. %FUFSNJOJOHUIFOBNFSFTPMVUJPOUJNFPVU ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at || connection_attempt_delay_expires_at else [

    user_specified_resolv_timeout_at, user_specified_connect_timeout_at ].compact.max end %VSJOHUIFJOJUJBMOBNFSFTPMVUJPO  OPEFTUJOBUJPOBEESFTTJTLOPXOZFU  TPFYFDVUJPOFOUFSTUIFMPXFSCSBODI 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC
  37. %FUFSNJOJOHUIFOBNFSFTPMVUJPOUJNFPVU ends_at = if resolution_store.any_addrinfos? # ... else [ user_specified_resolv_timeout_at,

    user_specified_connect_timeout_at ].compact.max end user_specified_resolv_timeout_at = resolv_timeout ? now + resolv_timeout : Float::INFINITY VTFS@TQFDJ fi FE@SFTPMW@UJNFPVU@BUJTTFUUP FJUIFSUIFFYQJSBUJPOUJNFPGSFTPMW@UJNFPVU PS'MPBU*/'*/*5: 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC
  38. %FUFSNJOJOHUIFOBNFSFTPMVUJPOUJNFPVU ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at || connection_attempt_delay_expires_at else [

    user_specified_resolv_timeout_at, user_specified_connect_timeout_at ].compact.max end user_specified_connect_timeout_at = nil VTFS@TQFDJ fi FE@DPOOFDU@UJNFPVU@BUSFNBJOT BUJUTJOJUJBMWBMVFPGOJM 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC
  39. %FUFSNJOJOHUIFOBNFSFTPMVUJPOUJNFPVU ends_at = if resolution_store.any_addrinfos? # ... else [ user_specified_resolv_timeout_at,

    user_specified_connect_timeout_at ].compact.max end "GUFSDPNQBDUJOHUIFBSSBZ  VTFS@TQFDJ fi FE@SFTPMW@UJNFPVU@BUJTSFUVSOFE 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC user_specified_resolv_timeout_at = resolv_timeout ? now + resolv_timeout : Float::INFINITY
  40. 4PJUTFUTUIFFYQJSBUJPOUJNFEF fi OFECZUIFTQFDJ fi DBUJPO JOSFTPMVUJPO@EFMBZ@FYQJSFT@BU %/4TFSWFS 4PDLFUUDQ 5$14PDLFUOFX resolution_delay_expires_at

    = now + RESOLUTION_DELAY "GUFSFJUIFSBEESFTTGBNJMZJTSFTPMWFE 4FOE%/4RVFSZGPS*1W 4FOE%/4RVFSZGPS*1W 3FUVSO*1W%/4SFTQPOTF fi STU 4UJMMXBJUJOHGPSUIF*1W%/4SFTQPOTF
  41. ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at || connection_attempt_delay_expires_at else [ user_specified_resolv_timeout_at,

    user_specified_connect_timeout_at ].compact.max end BOESFUVSOTUPUIJTDPOEJUJPOBMCSBODIBHBJO "GUFSFJUIFSBEESFTTGBNJMZJTSFTPMWFE 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC
  42. ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at || connection_attempt_delay_expires_at else [ user_specified_resolv_timeout_at,

    user_specified_connect_timeout_at ].compact.max end 5IJTUJNF TJODFUIFSFBSFBMSFBEZ DBOEJEBUFEFTUJOBUJPOBEESFTTFT  FYFDVUJPOFOUFSTUIFVQQFSCSBODI "GUFSFJUIFSBEESFTTGBNJMZJTSFTPMWFE 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC "OZDBOEJEBUFEFTUJOBUJPOBEESFTTFT 
  43. ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at || connection_attempt_delay_expires_at else # ...

    end # When the resolved addresses are IPv4 addresses resolution_delay_expires_at = now + RESOLUTION_DELAY *GSFTPMVUJPO@EFMBZ@FYQJSFT@BUIBTBWBMVF  UIBUWBMVFJTSFUVSOFE "GUFSFJUIFSBEESFTTGBNJMZJTSFTPMWFE 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC
  44. SFTPMVUJPO@EFMBZ@FYQJSFT@BUJTOPMPOHFSOFFEFE  TPJUJTTFUUPOJM %/4TFSWFS 4PDLFUUDQ 5$14PDLFUOFX if expired?(now, resolution_delay_expires_at) resolution_delay_expires_at

    = nil end "GUFSFJUIFSBEESFTTGBNJMZJTSFTPMWFE 4FOE%/4RVFSZGPS*1W 4FOE%/4RVFSZGPS*1W 3FUVSO*1W%/4SFTQPOTF fi STU 4UJMMXBJUJOHGPSUIF*1W%/4SFTQPOTF
  45. 4PJUTFUTUIFFYQJSBUJPOUJNFEF fi OFECZUIFTQFDJ fi DBUJPO JODPOOFDUJPO@BUUFNQU@EFMBZ@FYQJSFT@BU %/4TFSWFS 4PDLFUUDQ 5$14PDLFUOFX connection_attempt_delay_expires_at

    = now + CONNECTION_ATTEMPT_DELAY 4FSWFS 8BJUGPSUIFDPOOFDUJPOUPCFFTUBCMJTIFE 4UBSUBDPOOFDUJPOBUUFNQUUP*1W 4FOE%/4RVFSZGPS*1W 4FOE%/4RVFSZGPS*1W 3FUVSO*1W%/4SFTQPOTF fi STU 4UJMMXBJUJOHGPSUIF*1W%/4SFTQPOTF
  46. ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at || connection_attempt_delay_expires_at else [ user_specified_resolv_timeout_at,

    user_specified_connect_timeout_at ].compact.max end BOESFUVSOUPUIFCSBODI 8BJUGPSUIFDPOOFDUJPOUPCFFTUBCMJTIFE 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC
  47. ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at || connection_attempt_delay_expires_at else [ user_specified_resolv_timeout_at,

    user_specified_connect_timeout_at ].compact.max end *GBOZDBOEJEBUFEFTUJOBUJPOBEESFTTFTBSF TUJMMBWBJMBCMF  FYFDVUJPOFOUFSTUIFVQQFSCSBODI 8BJUGPSUIFDPOOFDUJPOUPCFFTUBCMJTIFE 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC "OZDBOEJEBUFEFTUJOBUJPOBEESFTTFT 
  48. ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at || connection_attempt_delay_expires_at else [ user_specified_resolv_timeout_at,

    user_specified_connect_timeout_at ].compact.max end .VTUCFOJM BOESFUVSOTDPOOFDUJPO@BUUFNQU@EFMBZ@FYQJSFT@BU 8BJUGPSUIFDPOOFDUJPOUPCFFTUBCMJTIFE connection_attempt_delay_expires_at = now + CONNECTION_ATTEMPT_DELAY 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC
  49. 5IJTJTSFQFBUFEFWFSZNTVOUJMOPBEESFTTFTSFNBJO %/4TFSWFS 4PDLFUUDQ 5$14PDLFUOFX 4FSWFS 8BJUGPSUIFDPOOFDUJPOUPCFFTUBCMJTIFE 4FOE%/4RVFSZGPS*1W 4FOE%/4RVFSZGPS*1W 3FUVSO*1W%/4SFTQPOTF fi

    STU 4UJMMXBJUJOHGPSUIF*1W%/4SFTQPOTF "GUFSNT TUBSUBOPUIFSBUUFNQU 4UBSUBDPOOFDUJPOBUUFNQUUP*1W "GUFSNT TUBSUBOPUIFSBUUFNQU
  50. if resolution_store.empty_addrinfos? user_specified_connect_timeout_at = connect_timeout ? now + connect_timeout :

    Float::INFINITY end 0ODFBDPOOFDUJPOBUUFNQUIBTCFFOTUBSUFEGPS UIFMBTUEFTUJOBUJPOBEESFTT BWBMVFJTBTTJHOFEUP VTFS@TQFDJ fi FE@DPOOFDU@UJNFPVU@BU 8BJUGPSOBNFSFTPMVUJPOPSDPOOFDUJPO 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC
  51. if resolution_store.empty_addrinfos? user_specified_connect_timeout_at = connect_timeout ? now + connect_timeout :

    Float::INFINITY end *GDPOOFDU@UJNFPVUJTTQFDJ fi FE  VTFS@TQFDJ fi FE@DPOOFDU@UJNFPVU@BUJTTFUUP JUTFYQJSBUJPOUJNF 8BJUGPSOBNFSFTPMVUJPOPSDPOOFDUJPO 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC 5IFVTFSTQFDJ fi FEFYQJSBUJPOUJNF
  52. if resolution_store.empty_addrinfos? user_specified_connect_timeout_at = connect_timeout ? now + connect_timeout :

    Float::INFINITY end 0UIFSXJTF JUJTTFUUP'MPBU*/'*/*5: UPNFBOXBJUJOEF fi OJUFMZ 8BJUGPSOBNFSFTPMVUJPOPSDPOOFDUJPO 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC NFBOTJOEF fi OJUFMZ
  53. ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at || connection_attempt_delay_expires_at else [ user_specified_resolv_timeout_at,

    user_specified_connect_timeout_at ].compact.max end 5PEPUIBU JUSFUVSOTUPUIFCSBODI 4JODFUIFSFBSFOPDBOEJEBUFEFTUJOBUJPOBEESFTTFT MFGU FYFDVUJPOFOUFSTUIFMPXFSCSBODI 8BJUGPSOBNFSFTPMVUJPOPSDPOOFDUJPO 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC "OZDBOEJEBUFEFTUJOBUJPOBEESFTTFT 
  54. ends_at = if resolution_store.any_addrinfos? # ... else [ user_specified_resolv_timeout_at, user_specified_connect_timeout_at

    ].compact.max end BOESFUVSOTXIJDIFWFSJTHSFBUFS VTFS@TQFDJ fi FE@SFTPMW@UJNFPVU@BUPS VTFS@TQFDJ fi FE@DPOOFDU@UJNFPVU@BU user_specified_resolv_timeout_at = resolv_timeout ? now + resolv_timeout : Float::INFINITY user_specified_connect_timeout_at = connect_timeout ? now + connect_timeout : Float::INFINITY 8BJUGPSOBNFSFTPMVUJPOPSDPOOFDUJPO 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC
  55. *GOFJUIFSOBNFSFTPMVUJPOOPSUIFDPOOFDUJPODPNQMFUFT XJUIJOUIFTQFDJ fi FEUJNF BUJNFPVUFSSPSJTSBJTFE %/4TFSWFS 4PDLFUUDQ 5$14PDLFUOFX 4FSWFS 8BJUGPSOBNFSFTPMVUJPOPSDPOOFDUJPO

    $BODFMUIFSFNBJOJOH%/4RVFSZ $BODFMUIFBUUFNQUT VTFS@TQFDJ fi FE@DPOOFDU@UJNFPVU@BU PSVTFS@TQFDJ fi FE@SFTPMW@UJNFPVU@BU
  56. 8IFOBMMOBNFSFTPMVUJPOJTDPNQMFUF if resolution_store.resolved?(:ipv4) if resolution_store.resolved?(:ipv6) # ... user_specified_resolv_timeout_at = nil

    end # ... end VTFS@TQFDJ fi FE@SFTPMW@UJNFPVU@BUJT OPMPOHFSOFFEFE TPJUJTTFUUPOJM 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC
  57. $POUJOVFTUBSUJOHDPOOFDUJPOBUUFNQUT if resolution_store.empty_addrinfos? user_specified_connect_timeout_at = connect_timeout ? now + connect_timeout

    : Float::INFINITY end 0ODFBDPOOFDUJPOBUUFNQUIBTCFFOTUBSUFEGPS UIFMBTUBEESFTT  VTFS@TQFDJ fi FE@DPOOFDU@UJNFPVU@BUJTTFUBHBJO 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC
  58. ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at || connection_attempt_delay_expires_at else [ user_specified_resolv_timeout_at,

    user_specified_connect_timeout_at ].compact.max end 5IJTJTUIFOUBLFOBTUIFFYQJSBUJPOUJNF user_specified_connect_timeout_at = connect_timeout ? now + connect_timeout : Float::INFINITY $POUJOVFTUBSUJOHDPOOFDUJPOBUUFNQUT 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC user_specified_resolv_timeout_at = nil
  59. GBTU@GBMMCBDLJTFOBCMFECZEFGBVMU  CVUJUDBOCFEJTBCMFEJOUIFTFUUJOHT 8IFOGBTU@GBMMCBDLJTEJTBCMFE UIFJNQMFNFOUBUJPOTPG4PDLFUUDQ BOE5$14PDLFUOFXSFNBJOVODIBOHFEGSPNUIPTFJO3VCZ # An argument to

    the method Socket.tcp(host, port, fast_fallback: false) TCPSocket.new(host, port, fast_fallback: false) # An accessor method on the Socket class Socket.tcp_fast_fallback = false # An environment variable TCP_NO_FAST_FALLBACK = 1
  60. OFUIUUQVTFEUIFUJNFPVUMJCSBSZUPUPXBJUGPSUIFPWFSBMMPQFSBUJPO  GSPNOBNFSFTPMVUJPOUPDPOOFDUJPOFTUBCMJTINFOU 5JNFPVU)BOEMJOHJOOFUIUUQ GSPN(MBTT@TBHB .BTBLJ.BUTVTIJUB IUUQTCVHTSVCZMBOHPSHJTTVFT Currently, we use

    Timeout in Net::HTTP and other standard libraries. lib/net/http.rb 945 s = Timeout.timeout(@open_timeout, Net::OpenTimeout) { 946 begin 947 TCPSocket.open(conn_address, conn_port, @local_host, @local_port) 948 rescue => e 949 raise e, "Failed to open TCP connection to " + 950 "#{conn_address}:#{conn_port} (#{e.message})" 951 end 952 } 5IFUJNFPVUMJCSBSZTNFUIPE
  61. 5IFUJNFPVUMJCSBSZXJUI3BDUPS 3VCZ require "timeout" r = Ractor.new do Timeout.timeout(1) do

    sleep 2 end end r.take )PXFWFS BTPG3VCZ UIFUJNFPVUMJCSBSZEJEOPUXPSLXFMM XJUI3BDUPS 6TJOHJUJOTJEFBOPONBJO3BDUPSXPVMESBJTFBOFSSPS # => Ractor::IsolationError can not access non-shareable objects in constant Timeout::State::GLOBAL_STATE by non-main ractor.
  62. 5IJTDPOOFDUJPOJTOPUFTUBCMJTIFEJNNFEJBUFMZ "GUFSNT DPOOFDU@UJNFPVUFYQJSFT %/4TFSWFS 4PDLFUUDQ 5$14PDLFUOFX 4FSWFS FH8IFOSFTPMW@UJNFPVUJTMPOHFSUIBODPOOFDU@UJNFPVU 4UBSUBDPOOFDUJPOBUUFNQUUP*1W NTQBTTFE

    4FOE%/4RVFSZGPS*1W 4FOE%/4RVFSZGPS*1W 3FUVSOUIF*1W%/4SFTQPOTF fi STU 8BJUJOHGPSUIF*1W%/4SFTQPOTF DPOOFDU@UJNFPVUNT SFTPMW@UJNFPVUNT
  63. )PXFWFS BUUIJTQPJOUSFTPMW@UJNFPVUTUJMMIBTNT SFNBJOJOH TPOPFSSPSJTSBJTFEUIFXBJUDPOUJOVFT %/4TFSWFS 4PDLFUUDQ 5$14PDLFUOFX 4FSWFS FH8IFOSFTPMW@UJNFPVUJTMPOHFSUIBODPOOFDU@UJNFPVU 4FOE%/4RVFSZGPS*1W

    4FOE%/4RVFSZGPS*1W 3FUVSOUIF*1W%/4SFTQPOTF fi STU 8BJUJOHGPS*1W NTMFGU SFTPMW@UJNFPVUNT 4UBSUBDPOOFDUJPOBUUFNQUUP*1W 4UJMMXBJUJOHGPSDPOOFDUJPO
  64. *OUIJTDBTF UIFPWFSBMMUJNFPVUJTOPUNT  UIFWBMVFPGDPOOFDU@UJNFPVU *UJTNT NT GPSBUPUBMPGNT 4PDLFUUDQ 5$14PDLFUOFX 4FSWFS

    FH8IFO$POOFDUJPO"UUFNQU%FMBZPDDVST $BODFMUIFDPOOFDUJPOUP# $BODFMUIFDPOOFDUJPOUP" 5IFPWFSBMMUJNFPVUNT NT DPOOFDU@UJNFPVUNT
  65. /PUVTJOHPQFO@UJNFPVUBOEPUIFSUJNFPVUPQUJPOTUPHFUIFS def self.tcp( host, port, ..., connect_timeout: nil, resolv_timeout: nil,

    open_timeout: nil, ..., & ) if open_timeout && (connect_timeout || resolv_timeout) raise ArgumentError, "Cannot specify open_timeout along with connect_timeout or resolv_timeout" end # ... end *GPQFO@UJNFPVUJTTQFDJ fi FEUPHFUIFSXJUI BOPUIFSUJNFPVUBSHVNFOU JUJTUSFBUFEBTJOWBMJEBOE BO"SHVNFOU&SSPSJTSBJTFE 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC .VTUCFSBJTFE "EEFE
  66. PQFO@UJNFPVUXJUIGBTU@GBMMCBDL ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at || connection_attempt_delay_expires_at else [

    user_specified_resolv_timeout_at, user_specified_connect_timeout_at ].compact.max end /FYU XFOFFEUPDPOTJEFSIPXUPNBLFGBTU@GBMMCBDL XPSLXJUIGBTU@GBMMCBDL 5IJTJTUIFDPEFBTPG3VCZ 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC *O3VCZ
  67. ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at || connection_attempt_delay_expires_at else [ user_specified_resolv_timeout_at,

    user_specified_connect_timeout_at ].compact.max end *GUIFSFBSFDBOEJEBUFEFTUJOBUJPOBEESFTTFT  JUSFUVSOTUIFUJNFXIFOUIFOFYUDPOOFDUJPOBUUFNQU DBOCFTUBSUFE PQFO@UJNFPVUXJUIGBTU@GBMMCBDL "OZDBOEJEBUFEFTUJOBUJPOBEESFTTFT  3FUVSOTXIFOUPTUBSUUIFOFYUDPOOFDUJPOBUUFNQU 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC *O3VCZ
  68. ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at || connection_attempt_delay_expires_at else [ user_specified_resolv_timeout_at,

    user_specified_connect_timeout_at ].compact.max end 0UIFSXJTF JUSFUVSOTUIFUJNF XIFOBUJNFPVUFSSPSTIPVMECFSBJTFE PQFO@UJNFPVUXJUIGBTU@GBMMCBDL 3FUVSOTXIFOUPSBJTFBUJNFPVUFSSPS "OZDBOEJEBUFEFTUJOBUJPOBEESFTTFT  'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC *O3VCZ
  69. ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at || connection_attempt_delay_expires_at else [ user_specified_resolv_timeout_at,

    user_specified_connect_timeout_at ].compact.max end 8JUIPQFO@UJNFPVU BUJNFPVUFSSPSOFFETUPCFSBJTFE BUUIFTQFDJ fi FEUJNFSFHBSEMFTTPGXIFUIFSUIFSFBSF BOZDBOEJEBUFEFTUJOBUJPOBEESFTTFT PQFO@UJNFPVUXJUIGBTU@GBMMCBDL "OZDBOEJEBUFEFTUJOBUJPOBEESFTTFT  'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC *O3VCZ
  70. def self.tcp_with_fast_fallback( host, port, ..., connect_timeout: nil, resolv_timeout: nil, open_timeout:

    nil, ) # ... resolution_delay_expires_at = nil connection_attempt_delay_expires_at = nil user_specified_connect_timeout_at = nil user_specified_open_timeout_at = open_timeout ? now + open_timeout : nil # ... end 8JUIUIJTJONJOE JOUIFNPEJ fi FEDPEF  BWBMVFJTBTTJHOFEUPVTFS@TQFDJ fi FE@PQFO@UJNFPVU@BU BUUIFTUBSUPGUIFNFUIPE PQFO@UJNFPVUXJUIGBTU@GBMMCBDL 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC *O3VCZ
  71. def self.tcp_with_fast_fallback( host, port, ..., connect_timeout: nil, resolv_timeout: nil, open_timeout:

    nil, ) # ... resolution_delay_expires_at = nil connection_attempt_delay_expires_at = nil user_specified_connect_timeout_at = nil user_specified_open_timeout_at = open_timeout ? now + open_timeout : nil # ... end *GPQFO@UJNFPVUJTDPO fi HVSFE  UIFWBSJBCMFJTTFUUPUIFUJNFXIFOPQFO@UJNFPVU XJMMFYQJSF PQFO@UJNFPVUXJUIGBTU@GBMMCBDL 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC *O3VCZ
  72. def self.tcp_with_fast_fallback( host, port, ..., connect_timeout: nil, resolv_timeout: nil, open_timeout:

    nil, ) # ... resolution_delay_expires_at = nil connection_attempt_delay_expires_at = nil user_specified_connect_timeout_at = nil user_specified_open_timeout_at = open_timeout ? now + open_timeout : nil # ... end 0UIFSXJTF JUJTTFUUPOJM PQFO@UJNFPVUXJUIGBTU@GBMMCBDL 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC *O3VCZ
  73. ends_at = if resolution_store.any_addrinfos? [(resolution_delay_expires_at || connection_attempt_delay_expires_at), user_specified_open_timeout_at].compact.min XJUIUIFFYQJSBUJPOUJNFGPSPQFO@UJNFPVU 

    PQFO@UJNFPVUXJUIGBTU@GBMMCBDL user_specified_open_timeout_at = open_timeout ? now + open_timeout : nil 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC *O3VCZ
  74. ends_at = if resolution_store.any_addrinfos? [(resolution_delay_expires_at || connection_attempt_delay_expires_at), user_specified_open_timeout_at].compact.min XJUIUIFFYQJSBUJPOUJNFGPSPQFO@UJNFPVU 

    BOEUIFFBSMJFSPOFJTSFUVSOFE PQFO@UJNFPVUXJUIGBTU@GBMMCBDL 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC user_specified_open_timeout_at = open_timeout ? now + open_timeout : nil *O3VCZ
  75. ends_at = if resolution_store.any_addrinfos? [(resolution_delay_expires_at || connection_attempt_delay_expires_at), user_specified_open_timeout_at].compact.min # ...

    end if expired?(now, user_specified_open_timeout_at) raise(IO::TimeoutError, "user specified timeout for #{host}:#{port}") end *GUIFPQFO@UJNFPVUFYQJSBUJPOUJNFIBT BMSFBEZQBTTFEXIFOUIFXBJUFOET  BUJNFPVUFSSPSJTSBJTFE PQFO@UJNFPVUXJUIGBTU@GBMMCBDL 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC .VTUCFSBJTFE *O3VCZ
  76. ends_at = if resolution_store.any_addrinfos? [(resolution_delay_expires_at || connection_attempt_delay_expires_at), user_specified_open_timeout_at].compact.min *GPQFO@UJNFPVUJTOPUTQFDJ fi

    FE  UIFWBMVFPGVTFS@TQFDJ fi FE@PQFO@UJNFPVU@BUJTOJM PQFO@UJNFPVUXJUIGBTU@GBMMCBDL 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC user_specified_open_timeout_at = open_timeout ? now + open_timeout : nil *O3VCZ
  77. ends_at = if resolution_store.any_addrinfos? [(resolution_delay_expires_at || connection_attempt_delay_expires_at), user_specified_open_timeout_at].compact.min *OUIBUDBTF BTCFGPSF

    UIFSFUVSOWBMVFJT UIFFYQJSBUJPOUJNFGPSFJUIFS3FTPMVUJPO%FMBZ PS$POOFDUJPO"UUFNQU%FMBZ PQFO@UJNFPVUXJUIGBTU@GBMMCBDL 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC 3FUVSOTXIFOUPTUBSUUIFOFYUDPOOFDUJPOBUUFNQU *O3VCZ
  78. ends_at = if resolution_store.any_addrinfos? [(resolution_delay_expires_at || connection_attempt_delay_expires_at), user_specified_open_timeout_at].compact.min elsif user_specified_open_timeout_at

    JGPQFO@UJNFPVUJTTQFDJ fi FE  JUJTUIFPOMZUJNFPVUUIBUDBODBVTFBUJNFPVUFSSPS PQFO@UJNFPVUXJUIGBTU@GBMMCBDL 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC *O3VCZ
  79. ends_at = if resolution_store.any_addrinfos? [(resolution_delay_expires_at || connection_attempt_delay_expires_at), user_specified_open_timeout_at].compact.min elsif user_specified_open_timeout_at

    user_specified_open_timeout_at else # ... end 4PUIFSFUVSOWBMVFJTTJNQMZ VTFS@TQFDJ fi FE@PQFO@UJNFPVU@BU PQFO@UJNFPVUXJUIGBTU@GBMMCBDL 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC user_specified_open_timeout_at = open_timeout ? now + open_timeout : nil *O3VCZ
  80. ends_at = if resolution_store.any_addrinfos? [(resolution_delay_expires_at || connection_attempt_delay_expires_at), user_specified_open_timeout_at].compact.min elsif user_specified_open_timeout_at

    user_specified_open_timeout_at else [ user_specified_resolv_timeout_at, user_specified_connect_timeout_at ].compact.max end *GVTFS@TQFDJ fi FE@PQFO@UJNFPVU@BUJTOJM  JUGBMMTCBDLUPUIFPUIFSVTFSTQFDJ fi FEUJNFPVUWBMVFT 5IJTNBJOUBJOTUIFCFIBWJPSCFGPSFUIFDIBOHF PQFO@UJNFPVUXJUIGBTU@GBMMCBDL 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC nil *O3VCZ
  81. ends_at = if resolution_store.any_addrinfos? [(resolution_delay_expires_at || connection_attempt_delay_expires_at), user_specified_open_timeout_at].compact.min elsif user_specified_open_timeout_at

    user_specified_open_timeout_at else [ user_specified_resolv_timeout_at, user_specified_connect_timeout_at ].compact.max end 8JUIUIJT PQFO@UJNFPVUJTOPXDPNQMFUF XIFOGBTU@GBMMCBDLJTFOBCMFE PQFO@UJNFPVUXJUIGBTU@GBMMCBDL 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC *O3VCZ
  82. def self.tcp_without_fast_fallback( host, port, ..., connect_timeout: nil, resolv_timeout: nil, )

    # ... Addrinfo.foreach(host, port, nil, :STREAM, timeout: resolv_timeout) {|ai| # ... } # ... end 5IJTJTUIF3VCZJNQMFNFOUBUJPO XIFOGBTU@GBMMCBDLJTEJTBCMFE PQFO@UJNFPVUXJUIPVUGBTU@GBMMCBDL *O3VCZ 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC
  83. def self.tcp_without_fast_fallback( host, port, ..., connect_timeout: nil, resolv_timeout: nil, )

    # ... Addrinfo.foreach(host, port, nil, :STREAM, timeout: resolv_timeout) {|ai| # ... } # ... end 5IFSFNBJOJOHUJNFVOUJMSFTPMW@UJNFPVUFYQJSFTJT BMSFBEZQBTTFEUPUIFNFUIPEPSGVODUJPOUIBU QFSGPSNTOBNFSFTPMVUJPOBTUIFUJNFPVUEVSBUJPO PQFO@UJNFPVUXJUIPVUGBTU@GBMMCBDL 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC "EESJOGPGPSFBDIDBMMT"EESJOGPHFUBEESJOGP JOUFSOBMMZXJUIUJNFPVU *O3VCZ
  84. def self.tcp_without_fast_fallback( host, port, ..., connect_timeout: nil, resolv_timeout: nil, open_timeout:

    nil ) # ... timeout = open_timeout ? open_timeout : resolv_timeout starts_at = current_clock_time Addrinfo.foreach(host, port, nil, :STREAM, timeout: timeout) {|ai| # ... } # ... end JGPQFO@UJNFPVUJTTQFDJ fi FE JUTWBMVFDBOCFQBTTFE BTUIFUJNFPVUWBMVFJOTUFBEPGSFTPMW@UJNFPVU TP UIBUOBNFSFTPMVUJPOUJNFTPVUBUUIFTQFDJ fi FEUJNF PQFO@UJNFPVUXJUIPVUGBTU@GBMMCBDL 6TFPQFO@UJNFPVUJOTUFBEPGSFTPMW@UJNFPVU 'PS4PDLFUUDQIUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC *O3VCZ "EEFE
  85. 5IFO JO3VCZ GBTU@GBMMCBDLXBTJOUSPEVDFE BOEPOMZUIBU JNQMFNFOUBUJPOIBOEMFEOBNFSFTPMVUJPOUJNFPVUT UJNFPVU "EESJOGPHFUBEESJOGP DPOOFDU@UJNFPVU SFTPMW@UJNFPVU PQFO@UJNFPVU

    4PDLFUUDQ5$14PDLFUOFX XJUIPVUGBTU@GBMMCBDL 4PDLFUUDQ5$14PDLFUOFX XJUIGBTU@GBMMCBDL "1*POMZ "1*POMZ 3VCZ
  86. 4PDLFUUDQ  ➡︎ "EESJOGPHFUBEESJOGP  ➡︎ BEESJOGP@T@HFUBEESJOGP ɹ ➡︎ BEESJOGP@MJTU@OFX

    ɹ ➡︎ DBMM@HFUBEESJOGP ɹɹ ➡︎ STPDL@HFUBEESJOGP "EESJOGPHFUBEESJOGPDBMMT STPDL@HFUBEESJOGP JOUFSOBMMZ 8IBUJTIBQQFOJOHXJUIUIFOBNFSFTPMVUJPOUJNFPVUT
  87. 4PDLFUUDQ  ➡︎ "EESJOGPHFUBEESJOGP  ➡︎ BEESJOGP@T@HFUBEESJOGP ɹ ➡︎ BEESJOGP@MJTU@OFX

    ɹ ➡︎ DBMM@HFUBEESJOGP ɹɹ ➡︎ STPDL@HFUBEESJOGP 5$14PDLFUOFXDBMMT STPDL@HFUBEESJOGP JOUFSOBMMZ UPP 8IBUJTIBQQFOJOHXJUIUIFOBNFSFTPMVUJPOUJNFPVUT 5$14PDLFUOFX  ➡︎ 5$14PDLFUJOJUJBMJ[F  ➡︎ STPDL@JOJU@JOFUTPDL ɹ ➡︎ JOJU@JOFUTPDL@JOUFSOBM ɹ ➡︎ STPDL@BEESJOGP ɹ ➡︎ STPDL@HFUBEESJOGP
  88. 4PDLFUUDQ  ➡︎ "EESJOGPHFUBEESJOGP  ➡︎ BEESJOGP@T@HFUBEESJOGP ɹ ➡︎ BEESJOGP@MJTU@OFX

    ɹ ➡︎ DBMM@HFUBEESJOGP ɹɹ ➡︎ STPDL@HFUBEESJOGP 8IBUUIFZIBWFJODPNNPO JTUIFDBMMUPSTPDL@HFUBEESJOGP  DPNNPO 8IBUJTIBQQFOJOHXJUIUIFOBNFSFTPMVUJPOUJNFPVUT 5$14PDLFUOFX  ➡︎ 5$14PDLFUJOJUJBMJ[F  ➡︎ STPDL@JOJU@JOFUTPDL ɹ ➡︎ JOJU@JOFUTPDL@JOUFSOBM ɹ ➡︎ STPDL@BEESJOGP ɹ ➡︎ STPDL@HFUBEESJOGP
  89. static struct rb_addrinfo * call_getaddrinfo( VALUE node, VALUE service, VALUE

    family, VALUE socktype, VALUE protocol, VALUE flags, int socktype_hack, VALUE timeout ) { // ... } 5IFDPEFUIBUDBMMTSTPDL@HFUBEESJOGP  8IBUJTIBQQFOJOHXJUIUIFOBNFSFTPMVUJPOUJNFPVUT IUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUSBEESJOGPD *O3VCZ
  90. static struct rb_addrinfo * call_getaddrinfo( VALUE node, VALUE service, VALUE

    family, VALUE socktype, VALUE protocol, VALUE flags, int socktype_hack, VALUE timeout ) { // ... } 5IFDPEFUIBUDBMMTSTPDL@HFUBEESJOGP  BMSFBEZUBLFTUIFVTFSTQFDJ fi FEUJNFPVUWBMVF BTBOBSHVNFOU 8IBUJTIBQQFOJOHXJUIUIFOBNFSFTPMVUJPOUJNFPVUT 5IFVTFSTQFDJ fi FEUJNFPVUWBMVF IUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUSBEESJOGPD *O3VCZ
  91. static struct rb_addrinfo * call_getaddrinfo( VALUE node, VALUE service, VALUE

    family, VALUE socktype, VALUE protocol, VALUE flags, int socktype_hack, VALUE timeout ) { // ... res = rsock_getaddrinfo(node, service, &hints, socktype_hack); // ... } #VUJOGBDU  JUXBTOPUCFJOHQBTTFEUPSTPDL@HFUBEESJOGP  8IBUJTIBQQFOJOHXJUIUIFOBNFSFTPMVUJPOUJNFPVUT 5IFWBMVFJTOPUQBTTFE  5IFVTFSTQFDJ fi FEUJNFPVUWBMVF IUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUSBEESJOGPD *O3VCZ
  92. struct rb_addrinfo* rsock_getaddrinfo( VALUE host, VALUE port, struct addrinfo *hints,

    int socktype_hack ) { // ... } "OEPOUIFSTPDL@HFUBEESJOGP TJEF UIFSFXBTOP QBSBNFUFSGPSSFDFJWJOHUIFWBMVF5IFVTFSTQFDJ fi FE UJNFPVUWBMVFTJNQMZWBOJTIFEBUUIJTQPJOU 5IFVTFSTQFDJ fi FEUJNFPVUWBMVFDBOOPUCFQBTTFE 8IBUJTIBQQFOJOHXJUIUIFOBNFSFTPMVUJPOUJNFPVUT IUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUSBEESJOGPD *O3VCZ
  93. 'JYUIFOBNFSFTPMVUJPOUJNFPVUT struct rb_addrinfo* rsock_getaddrinfo( VALUE host, VALUE port, struct addrinfo

    *hints, int socktype_hack VALUE timeout ) { // ... } 4P STPDL@HFUBEESJOGP XBTDIBOHFEUPSFDFJWF UIFVTFSTQFDJ fi FEUJNFPVUWBMVFBTXFMM "EEFE IUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUSBEESJOGPD *O3VCZ
  94. struct rb_addrinfo* rsock_getaddrinfo( VALUE host, VALUE port, struct addrinfo *hints,

    int socktype_hack VALUE timeout ) { // ... int t = NIL_P(timeout) ? -1 : rsock_value_timeout_to_msec(timeout); error = rb_getaddrinfo(hostp, portp, hints, &ai, t); // ... } *UUIFOQBTTFTUIBUWBMVFGVSUIFSEPXOUP UIFGVODUJPOJUDBMMTJOUFSOBMMZ 'JYUIFOBNFSFTPMVUJPOUJNFPVUT IUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUSBEESJOGPD "EEFE *O3VCZ
  95. static void * wait_getaddrinfo(void *ptr) { // ... long msec

    = arg->timeout; if (msec == 0) { arg->cancelled = 1; arg->timedout = 1; } else if (msec > 0) { rb_native_cond_timedwait(&arg->cond, &arg->lock, msec); if (!arg->done) { arg->cancelled = 1; arg->timedout = 1; } // ... } // ... } 8IFOXBJUJOHGPSOBNFSFTPMVUJPO  JUOPXUFSNJOBUFTUIFXBJUBGUFSUIFTQFDJ fi FEUJNF JGBUJNFPVUWBMVFJTHJWFO 'JYUIFOBNFSFTPMVUJPOUJNFPVUT 8BJUVOUJMUIFOBNFSFTPMVUJPOUJNFPVUFYQJSFT 5IFVTFSTQFDJ fi FEUJNFPVUWBMVF IUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUSBEESJOGPD *O3VCZ
  96. PQFO@UJNFPVUXJUIPVUGBTU@GBMMCBDL 4PDLFUUDQ  ➡︎ "EESJOGPHFUBEESJOGP  ➡︎ BEESJOGP@T@HFUBEESJOGP ɹ ➡︎

    BEESJOGP@MJTU@OFX ɹ ➡︎ DBMM@HFUBEESJOGP ɹɹ ➡︎ STPDL@HFUBEESJOGP "TBSFTVMU OBNFSFTPMVUJPODBOOPXUJNFPVUJO 4PDLFUUDQ "EESJOGPHFUBEESJOGP BOE5$14PDLFUOFX 5$14PDLFUOFX  ➡︎ 5$14PDLFUJOJUJBMJ[F  ➡︎ STPDL@JOJU@JOFUTPDL ɹ ➡︎ JOJU@JOFUTPDL@JOUFSOBM ɹ ➡︎ STPDL@BEESJOGP ɹ ➡︎ STPDL@HFUBEESJOGP 'JYFE $BOUJNFPVU
  97. starts_at = current_clock_time Addrinfo.foreach(host, port, nil, :STREAM, timeout:) {|ai| #

    ... timeout = if open_timeout t = open_timeout - (current_clock_time - starts_at) t.negative? ? 0 : t # ... end # ... } 4P CFGPSFTUBSUJOHUIFDPOOFDUJPOBUUFNQU  JUPCUBJOTUIFSFNBJOJOHUJNFVOUJM PQFO@UJNFPVUFYQJSFT PQFO@UJNFPVUXJUIPVUGBTU@GBMMCBDL IUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC 5IFSFNBJOJOHUJNFVOUJMPQFO@UJNFPVUFYQJSFT
  98. starts_at = current_clock_time Addrinfo.foreach(host, port, nil, :STREAM, timeout:) {|ai| #

    ... timeout = if open_timeout t = open_timeout - (current_clock_time - starts_at) t.negative? ? 0 : t # ... end sock = local_addr ? ai.connect_from(local_addr, timeout: timeout) : ai.connect(timeout: timeout) # ... } BOEQBTTFTJUBTUIFUJNFPVUEVSBUJPO GPSUIFDPOOFDUJPOBUUFNQU PQFO@UJNFPVUXJUIPVUGBTU@GBMMCBDL IUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC 8BJUVOUJMUIFUJNFPVUFYQJSFT 5IFSFNBJOJOHUJNFVOUJMPQFO@UJNFPVUFYQJSFT
  99. starts_at = current_clock_time Addrinfo.foreach(host, port, nil, :STREAM, timeout:) {|ai| #

    ... timeout = if open_timeout t = open_timeout - (current_clock_time - starts_at) t.negative? ? 0 : t # ... end sock = local_addr ? ai.connect_from(local_addr, timeout: timeout) : ai.connect(timeout: timeout) # ... } *GUIBUDPOOFDUJPOBUUFNQUGBJMT UIFSFNBJOJOHUJNFJT VQEBUFECFGPSFUIFOFYUDPOOFDUJPOBUUFNQUJTTUBSUFE PQFO@UJNFPVUXJUIPVUGBTU@GBMMCBDL IUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC 6QEBUFPOSFNBJOJOHUJNFVOUJMUJNFPVU
  100. starts_at = current_clock_time Addrinfo.foreach(host, port, nil, :STREAM, timeout:) {|ai| #

    ... timeout = if open_timeout t = open_timeout - (current_clock_time - starts_at) t.negative? ? 0 : t # ... end sock = local_addr ? ai.connect_from(local_addr, timeout: timeout) : ai.connect(timeout: timeout) # ... } 0ODFUIFSFNBJOJOHUJNFJTFYIBVTUFE  BUJNFPVUFSSPSJTSBJTFE PQFO@UJNFPVUXJUIPVUGBTU@GBMMCBDL IUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC .VTUCFSBJTFE 6QEBUFPOSFNBJOJOHUJNFVOUJMUJNFPVU
  101. starts_at = current_clock_time Addrinfo.foreach(host, port, nil, :STREAM, timeout:) {|ai| #

    ... timeout = if open_timeout t = open_timeout - (current_clock_time - starts_at) t.negative? ? 0 : t else connect_timeout end sock = local_addr ? ai.connect_from(local_addr, timeout: timeout) : ai.connect(timeout: timeout) # ... } *GPQFO@UJNFPVUJTOPUTQFDJ fi FE UIFWBMVFPG DPOOFDU@UJNFPVUJTVTFEBTUIFDPOOFDUJPOUJNFPVU 5IJTNBJOUBJOTUIFCFIBWJPSCFGPSFUIFDIBOHF PQFO@UJNFPVUXJUIPVUGBTU@GBMMCBDL 8BJUVOUJMUIFUJNFPVUFYQJSFT PSJOEF fi OJUFMZ 5IFWBMVFTQFDJ fi FEGPSDPOOFDU@UJNFPVU PSOJM IUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC
  102. starts_at = current_clock_time Addrinfo.foreach(host, port, nil, :STREAM, timeout:) {|ai| #

    ... timeout = if open_timeout t = open_timeout - (current_clock_time - starts_at) t.negative? ? 0 : t else connect_timeout end sock = local_addr ? ai.connect_from(local_addr, timeout: timeout) : ai.connect(timeout: timeout) # ... } 8JUIUIJT PQFO@UJNFPVUJTBMTPDPNQMFUF XIFOGBTU@GBMMCBDLJTEJTBCMFE PQFO@UJNFPVUXJUIPVUGBTU@GBMMCBDL IUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUMJCTPDLFUSC
  103. *OBEEJUJPO UIFUJNFPVUBSHVNFOUPG"EESJOGPHFUBEESJOGP fi OBMMZCFDBNFF ff FDUJWFGPSUIF fi STUUJNFTJODF3VCZ UJNFPVU "EESJOGPHFUBEESJOGP

    DPOOFDU@UJNFPVU SFTPMW@UJNFPVU PQFO@UJNFPVU 4PDLFUUDQ5$14PDLFUOFX XJUIPVUGBTU@GBMMCBDL 4PDLFUUDQ5$14PDLFUOFX XJUIGBTU@GBMMCBDL fi xed fi xed
  104. 3FNPWFOFUIUUQ`TEFQFOEFODZPOUIFUJNFPVUMJCSBSZ 5IJTSFTPMWFEBMPOHTUBOEJOHDPODFSOEBUJOHCBDLUP UIF3VCZEFWFMPQNFOUFSB GSPN(MBTT@TBHB .BTBLJ.BUTVTIJUB IUUQTCVHTSVCZMBOHPSHJTTVFT Currently, we use Timeout

    in Net::HTTP and other standard libraries. lib/net/http.rb 945 s = Timeout.timeout(@open_timeout, Net::OpenTimeout) { 946 begin 947 TCPSocket.open(conn_address, conn_port, @local_host, @local_port) 948 rescue => e 949 raise e, "Failed to open TCP connection to " + 950 "#{conn_address}:#{conn_port} (#{e.message})" 951 end 952 } 5IFUJNFPVUMJCSBSZTNFUIPE
  105. 5IFUJNFPVUMJCSBSZXJUI3BDUPS 3VCZ require "timeout" r = Ractor.new do Timeout.timeout(1) do

    sleep 2 end end r.take 'PSUIFSFDPSE UIFJTTVFCFUXFFO3BDUPSBOEUIFUJNFPVUMJCSBSZ UIBUMFEUPUIFJOUSPEVDUJPOPGPQFO@UJNFPVUXBTSFTPMWFE JO3VCZUISPVHIJNQSPWFNFOUTUP3BDUPS 5PEBZ UIFUJNFPVUMJCSBSZDBOCFVTFEJOTJEFBOPONBJO3BDUPS # => no exception in Ruby 4.0!