Bad file descriptor thrown while making request on Windows
ZumiKua opened this issue · 3 comments
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
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?
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.
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.