PATCH request fails but PUT works
I'm stumped. What am I doing wrong?
require 'jsonclient'
hostdb_base_url = 'http://ourserver.our.org:8000'
hostdb_api_url = "#{hostdb_base_url}/api/v1"
fqdn = 'rcf-test-ubuntu.our.org'
now = Time.now
datestr = "#{now.year}-#{now.month}-#{now.day} #{now.hour}:#{now.min}"
client = JSONClient.new
response = client.get("#{hostdb_api_url}/device/?name=#{fqdn}&format=json")
devices = response.content['objects']
device_uri = devices.first['resource_uri']
puts "Trying to PATCH #{hostdb_base_url}#{device_uri}"
response = client.patch("#{hostdb_base_url}#{device_uri}", {:last_checkin => datestr})
Results in the following:
Trying to PATCH http://ourserver.our.org:8000/api/v1/device/767/
httpclient-2.7.1/lib/httpclient/session.rb:795:in `block in parse_header': HTTPClient::KeepAliveDisconnected: (HTTPClient::KeepAliveDisconnected)
from /opt/chef/embedded/lib/ruby/2.1.0/timeout.rb:91:in `block in timeout'
from /opt/chef/embedded/lib/ruby/2.1.0/timeout.rb:101:in `call'
from /opt/chef/embedded/lib/ruby/2.1.0/timeout.rb:101:in `timeout'
from /opt/chef/embedded/lib/ruby/gems/2.1.0/gems/httpclient-2.7.1/lib/httpclient/session.rb:788:in `parse_header'
from /opt/chef/embedded/lib/ruby/gems/2.1.0/gems/httpclient-2.7.1/lib/httpclient/session.rb:771:in `read_header'
from /opt/chef/embedded/lib/ruby/gems/2.1.0/gems/httpclient-2.7.1/lib/httpclient/session.rb:547:in `get_header'
from /opt/chef/embedded/lib/ruby/gems/2.1.0/gems/httpclient-2.7.1/lib/httpclient.rb:1294:in `do_get_header'
from /opt/chef/embedded/lib/ruby/gems/2.1.0/gems/httpclient-2.7.1/lib/httpclient.rb:1241:in `do_get_block'
from /opt/chef/embedded/lib/ruby/gems/2.1.0/gems/httpclient-2.7.1/lib/httpclient.rb:1021:in `block in do_request'
from /opt/chef/embedded/lib/ruby/gems/2.1.0/gems/httpclient-2.7.1/lib/httpclient.rb:1134:in `rescue in protect_keep_alive_disconnected'
from /opt/chef/embedded/lib/ruby/gems/2.1.0/gems/httpclient-2.7.1/lib/httpclient.rb:1128:in `protect_keep_alive_disconnected'
from /opt/chef/embedded/lib/ruby/gems/2.1.0/gems/httpclient-2.7.1/lib/httpclient.rb:1016:in `do_request'
from /opt/chef/embedded/lib/ruby/gems/2.1.0/gems/httpclient-2.7.1/lib/httpclient.rb:858:in `request'
from /opt/chef/embedded/lib/ruby/gems/2.1.0/gems/httpclient-2.7.1/lib/jsonclient.rb:29:in `request'
from /opt/chef/embedded/lib/ruby/gems/2.1.0/gems/httpclient-2.7.1/lib/httpclient.rb:749:in `patch'
from ./_update-basic.rb:19:in `<main>'
root@rcf-test-ubuntu:/tmp#
This is httpclient 2.7.1 from rubygems.
Turns out that switching from PATCH to PUT works.
However, testing with rest-client's PATCH (https://rubygems.org/gems/rest-client/) works fine.
HTTP put is supposed to be idempotent, patch is not. Which means if a put failed, it can be transparently re-tried, but a patch can not be.
I'm guessing HTTPClient has no way to notice a dropped persistent connection until it tries to make a request and get an error. It can transparently re-try idempotent request methods, but not non-idempotent request methods.
You can probably tell HTTPClient not to use persistent connections?
Turns out that switching from PATCH to PUT works.
However, testing with rest-client's PATCH (https://rubygems.org/gems/rest-client/) works fine.
Right, you already said that? I don't know anything about rest-client, it may not be using persistent HTTP keep-alive connections at all in which case the issue isn't present (which is why I suggested trying to tell HTTPClient to not use persistent connections for your case), or it may be violating the HTTP spec. Or something else.
Oops. Sorry. I found a browser tab open with my comment not apparently submitted yet, so I submitted it.
We've just settled on using PUT as it works for our specific use case.
If you (whomever) feel this isn't a bug in httpclient, I guess close?
I'm not actually a committer, see what @nahi says!
@jblaine Sorry for late response. I guess something I'm not aware of is happening at parsing 'PATCH' response. Could you try to add
client.debug_dev = STDERR
and try PATCH request? I want to see wiredump.
@jrochkind yeah, PUT should be idempotent but at this point HTTPClient does not assume that and does no retry based on method type.
Hmm. This works now with httpclient-2.8.3
[@gazoo:~] $ ruby test.rb
Trying to PATCH http://our-server.example.org:8000/api/v1/device/910/
[@gazoo:~] $