{"action":"created","issue":{"url":"https://api.github.com/repos/igrigorik/http-2/issues/50","repository_url":"https://api.github.com/repos/igrigorik/http-2","labels_url":"https://api.github.com/repos/igrigorik/http-2/issues/50/labels{/name}","comments_url":"https://api.github.com/repos/igrigorik/http-2/issues/50/comments","events_url":"https://api.github.com/repos/igrigorik/http-2/issues/50/events","html_url":"https://github.com/igrigorik/http-2/issues/50","id":136713578,"number":50,"title":"Errors eaten by lib when running threaded","user":{"login":"ostinelli","id":110142,"avatar_url":"https://avatars.githubusercontent.com/u/110142?v=3","gravatar_id":"","url":"https://api.github.com/users/ostinelli","html_url":"https://github.com/ostinelli","followers_url":"https://api.github.com/users/ostinelli/followers","following_url":"https://api.github.com/users/ostinelli/following{/other_user}","gists_url":"https://api.github.com/users/ostinelli/gists{/gist_id}","starred_url":"https://api.github.com/users/ostinelli/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ostinelli/subscriptions","organizations_url":"https://api.github.com/users/ostinelli/orgs","repos_url":"https://api.github.com/users/ostinelli/repos","events_url":"https://api.github.com/users/ostinelli/events{/privacy}","received_events_url":"https://api.github.com/users/ostinelli/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":14,"created_at":"2016-02-26T14:31:37Z","updated_at":"2016-04-28T23:31:38Z","closed_at":"2016-03-29T17:08:31Z","body":"Hello,\r\nFirst of all - thank you for providing the first ruby HTTP/2 library.\r\n\r\nI'm trying to implement a realistic client example that uses your library. The one you provide is great, however it is missing the practical scenario of having a client socket continuously listening for incoming responses and events (to my understanding, basically HTTP/2 requires 2-way sockets), while still allowing library users to send out frames.\r\n\r\nOne possible choice is to have a thread dedicated to listening, so I have coded a very simple example on how to do so. However, any errors that are generated in the thread appear to be eaten up by the library.\r\n\r\nTry this code:\r\n\r\n```ruby\r\nrequire 'socket'\r\nrequire 'uri'\r\nrequire 'http/2'\r\n\r\nclass Client\r\n\r\n  def initialize\r\n    @uri = URI.parse(\"http://106.186.112.116\")\r\n\r\n    @socket      = nil\r\n    @read_thread = nil\r\n\r\n    ensure_socket\r\n  end\r\n\r\n  def get\r\n    headers = {\r\n      ':scheme' => @uri.scheme,\r\n      ':method' => 'GET',\r\n      ':path'   => \"/\",\r\n      'host'    => @uri.host\r\n    }\r\n    stream  = h2.new_stream\r\n\r\n    ensure_socket\r\n\r\n    stream.headers(headers, end_stream: true)\r\n\r\n    receive\r\n  end\r\n\r\n  def ensure_socket\r\n    return if @socket\r\n\r\n    @socket = TCPSocket.new(@uri.host, @uri.port)\r\n\r\n  rescue SocketError => e\r\n    puts \"Could not connect to socket (#{e.class} exception: #{e.message})\"\r\n    close\r\n  end\r\n\r\n  def h2\r\n    @h2 ||= HTTP2::Client.new.tap do |h2|\r\n      h2.on(:frame) do |bytes|\r\n        puts \"Sending bytes: #{bytes.unpack(\"H*\").first}\"\r\n        @socket.print bytes\r\n        @socket.flush\r\n      end\r\n\r\n      h2.on(:frame_sent) do |frame|\r\n        puts \"Sent frame: #{frame.inspect}\"\r\n      end\r\n\r\n      h2.on(:frame_received) do |frame|\r\n        puts \"Received frame: #{frame.inspect}\"\r\n\r\n        # raise \"EXPLODE HERE\"\r\n      end\r\n    end\r\n  end\r\n\r\n  def receive\r\n    return if @read_thread\r\n\r\n    @read_thread = Thread.new do\r\n      loop do\r\n        begin\r\n          data = @socket.read_nonblock(1024)\r\n        rescue Errno::EAGAIN\r\n          retry\r\n        end\r\n\r\n        begin\r\n          h2 << data\r\n        rescue => e\r\n          puts \"#{e.class} exception: #{e.message} - closing socket.\"\r\n          e.backtrace.each { |l| puts \"\\t\" + l }\r\n          close\r\n        end\r\n\r\n        break unless @socket && !@socket.closed? && !@socket.eof?\r\n      end\r\n\r\n      close\r\n    end\r\n\r\n    @read_thread.abort_on_exception = true\r\n  end\r\n\r\n  def close\r\n    @socket.close if @socket && !@socket.closed?\r\n    @read_thread.exit if @read_thread\r\n\r\n    @socket      = nil\r\n    @h2          = nil\r\n    @read_thread = nil\r\n  end\r\nend\r\n\r\nc = Client.new\r\nc.get\r\n\r\nwhile true\r\n  sleep 1\r\nend\r\n```\r\n\r\nRun it as is, and this will issue a `GET` request to the http://106.186.112.116 test server. Everything should just work, and you will see the response frames. You can also issue multiple `c.get` instructions, and they all will work.\r\n\r\nNow, uncomment the line `# raise \"EXPLODE HERE\"` and run again. You will see the following:\r\n\r\n```\r\nHTTP2::Error::ProtocolError exception: HTTP2::Error::ProtocolError - closing socket.\r\n\t/Users/roberto/.rvm/gems/ruby-2.3.0@apnotic/gems/http-2-0.8.0/lib/http/2/connection.rb:650:in `connection_error'\r\n\t/Users/roberto/.rvm/gems/ruby-2.3.0@apnotic/gems/http-2-0.8.0/lib/http/2/connection.rb:324:in `rescue in receive'\r\n\t/Users/roberto/.rvm/gems/ruby-2.3.0@apnotic/gems/http-2-0.8.0/lib/http/2/connection.rb:163:in `receive'\r\n\ttest.rb:75:in `block (2 levels) in receive'\r\n\ttest.rb:67:in `loop'\r\n\ttest.rb:67:in `block in receive'\r\n```\r\n\r\nObviously this isn't the error that one would like to see in the logs.\r\n\r\nDo you have any recommendations to fix this, or an example of a realistic client that can keep on listening for server events?\r\n\r\nThank you,\r\nr."},"comment":{"url":"https://api.github.com/repos/igrigorik/http-2/issues/comments/215592491","html_url":"https://github.com/igrigorik/http-2/issues/50#issuecomment-215592491","issue_url":"https://api.github.com/repos/igrigorik/http-2/issues/50","id":215592491,"user":{"login":"igrigorik","id":10652,"avatar_url":"https://avatars.githubusercontent.com/u/10652?v=3","gravatar_id":"","url":"https://api.github.com/users/igrigorik","html_url":"https://github.com/igrigorik","followers_url":"https://api.github.com/users/igrigorik/followers","following_url":"https://api.github.com/users/igrigorik/following{/other_user}","gists_url":"https://api.github.com/users/igrigorik/gists{/gist_id}","starred_url":"https://api.github.com/users/igrigorik/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/igrigorik/subscriptions","organizations_url":"https://api.github.com/users/igrigorik/orgs","repos_url":"https://api.github.com/users/igrigorik/repos","events_url":"https://api.github.com/users/igrigorik/events{/privacy}","received_events_url":"https://api.github.com/users/igrigorik/received_events","type":"User","site_admin":false},"created_at":"2016-04-28T23:31:37Z","updated_at":"2016-04-28T23:31:37Z","body":"Ha! You've been busy.. :)\r\n\r\nNice work! Reading through the code..\r\n- there is no way to pass through request priorities, right?\r\n- response streaming? It'd be nice to have a way to consume it without buffering the whole response.\r\n- hook for receiving server push?\r\n\r\nI guess I should probably leave these as issues on the repo.."}}