socketry / async-http

MIT License
298 stars 45 forks source link

Bad file descriptor thrown while making request on Windows #163

Open ZumiKua opened 1 week ago

ZumiKua commented 1 week ago
  0.0s     warn: Async::Task [oid=0x244] [ec=0x258] [pid=13816] [2024-06-21 15:10:44 +0800]
               | Task may have ended with unhandled exception.
               |   Errno::EBADF: Bad file descriptor @ io_fillbuf - fd:5 C:/WINDOWS/System32/drivers/etc/hosts
               |   → C:/Ruby31-x64/lib/ruby/3.1.0/resolv.rb 193:in `each'
               |     C:/Ruby31-x64/lib/ruby/3.1.0/resolv.rb 193:in `block (2 levels) in lazy_initialize'
               |     C:/Ruby31-x64/lib/ruby/3.1.0/resolv.rb 192:in `open'
               |     C:/Ruby31-x64/lib/ruby/3.1.0/resolv.rb 192:in `block in lazy_initialize'
               |     C:/Ruby31-x64/lib/ruby/3.1.0/resolv.rb 188:in `synchronize'
               |     C:/Ruby31-x64/lib/ruby/3.1.0/resolv.rb 188:in `lazy_initialize'
               |     C:/Ruby31-x64/lib/ruby/3.1.0/resolv.rb 236:in `each_address'
               |     C:/Ruby31-x64/lib/ruby/3.1.0/resolv.rb 116:in `block in each_address'
               |     C:/Ruby31-x64/lib/ruby/3.1.0/resolv.rb 115:in `each'
               |     C:/Ruby31-x64/lib/ruby/3.1.0/resolv.rb 115:in `each_address'
               |     C:/Ruby31-x64/lib/ruby/3.1.0/resolv.rb 102:in `getaddresses'
               |     C:/Ruby31-x64/lib/ruby/3.1.0/resolv.rb 51:in `getaddresses'
               |     C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/async-2.12.0/lib/async/scheduler.rb 195:in `address_resolve'
               |     C:/Ruby31-x64/lib/ruby/3.1.0/socket.rb 227:in `getaddrinfo'
               |     C:/Ruby31-x64/lib/ruby/3.1.0/socket.rb 227:in `foreach'
               |     C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/io-endpoint-0.10.3/lib/io/endpoint/host_endpoint.rb 40:in `connect'
               |     C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/io-endpoint-0.10.3/lib/io/endpoint/ssl_endpoint.rb 155:in `connect'
               |     C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/async-http-0.67.1/lib/async/http/endpoint.rb 189:in `connect'
               |     C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/async-http-0.67.1/lib/async/http/client.rb 197:in `block in make_pool'
               |     C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/async-pool-0.6.1/lib/async/pool/controller.rb 286:in `create_resource'
               |     C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/async-pool-0.6.1/lib/async/pool/controller.rb 341:in `get_resource'
               |     C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/async-pool-0.6.1/lib/async/pool/controller.rb 305:in `block in available_resource'
               |     C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/async-2.12.0/lib/async/semaphore.rb 87:in `acquire'
               |     C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/async-pool-0.6.1/lib/async/pool/controller.rb 304:in `available_resource'
               |     C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/async-pool-0.6.1/lib/async/pool/controller.rb 268:in `wait_for_resource'
               |     C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/async-pool-0.6.1/lib/async/pool/controller.rb 117:in `acquire'
               |     C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/async-http-0.67.1/lib/async/http/client.rb 103:in `call'
               |     C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/protocol-http-0.26.5/lib/protocol/http/middleware.rb 43:in `call'
               |     C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/protocol-http-0.26.5/lib/protocol/http/accept_encoding.rb 35:in `call'
               |     C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/async-http-0.67.1/lib/async/http/internet.rb 50:in `call'
               |     C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/async-http-0.67.1/lib/async/http/internet.rb 63:in `block (2 levels) in <class:Internet>'
               |     ./a.rb:6 in `block in <main>'
               |     C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/async-2.12.0/lib/async/task.rb 164:in `block in run'
               |     C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/async-2.12.0/lib/async/task.rb 377:in `block in schedule'

Ruby version is ruby 3.1.3p185 (2022-11-24 revision 1a6b16756e) [x64-mingw-ucrt] async http version is 0.67.1

It seems that this exception is thrown while calling Resolv.getaddresses, if I call this method manually, this exception goes away.

require 'async'
require 'async/http/internet'
p Resolv.getaddresses("example.com") # comment this line will make this code throw.
Async do
  internet = Async::HTTP::Internet.new
  response = internet.get("https://example.com")
  p response.read
ensure
  internet.close
end
ioquatix commented 1 week ago

I see the issue but I'm not able to fix it at this time. I'm planning to support IOCP on Windows which should fix this. Are you able to use WSL2 instead?

ZumiKua commented 1 week ago

Thanks for your reply!

The workaround of calling Resolv.getaddresses is sufficient for me (I'm writing a small one-time use script), so no WSL2 is needed I think.

Please take your time to fix this issue, thanks again for your wonderful work.

ioquatix commented 1 week ago

The reason why it works is because file IO is not working correctly in the fiber scheduler. By doing Resolv.getaddresses("example.com") outside of the Async{} block, it's loading the hosts file from disk and caching it.