httprb / http

HTTP (The Gem! a.k.a. http.rb) - a fast Ruby HTTP client with a chainable API, streaming support, and timeouts
MIT License
3.01k stars 321 forks source link

Add .retriable feature to Http #598

Closed Bertg closed 4 months ago

Bertg commented 4 years ago

Based on the great initial POC of @ixti this should complete #595

Remarks:

Bertg commented 4 years ago

@paul & @ixti If you have any remarks on the PR, let me know, and I'll see to them

ixti commented 4 years ago

I had no time to do a full review, but there's one thing that I would like to be changed. Default list of statuses to retry should be 5XX. So probably for statuses it's better to provide proc.

Bertg commented 4 years ago

@ixti Took your feedback, and made the 500+ range auto retry.

However, I would argue that the library should not rely any status code by default. Here is why:

When a server is throwing 500 there is a good chance that it is experiencing trouble. By retrying by default we are making the situation worse. The same logic if followed in the faraday gem.

Bertg commented 4 years ago

I'll also wait to to comply with the code climate feedback, until the all human feedback is processed ;)

Bertg commented 4 years ago

I think handling different types of retry statuses is unneeded complication and supporting proc only is more than enough - it will handle all the cases.

The idea is to allow for a beautiful interface for the developer.

HTTP.retriable(retry_statuses: 400..499)
HTTP.retriable(retry_statuses: [404, 500..599])

looks a lot better than

HTTP.retriable(retry_statuses: ->(s) {  (400..499).cover?(s) })
HTTP.retriable((retry_statuses: ->(s) { s == 404 || (400..499).cover?(s) })

I could move that convienece into Chainable#retriable but I don't believe that is the best place for it.

Also I think exception retry proc and status retry should be separated.

I get that. However one of the options a developer can pass is a proc should_retry to decide to retry or not, based on exception or status code. I'm trying to use the same logic here. I guess I could make a method that looks something like this:


def perform(client, req)
  1.upto(Float::INFINITY) do |attempt| # infinite loop with index
    err, res = try_request { yield }

    if retry_request?(req, err, res, attempt)
      begin
        wait_for_retry_or_raise(req, err, res, attempt)
      ensure
        # ...
        client.close
      end
    elsif err
      client.close
      raise err
    elsif res
      return res
    end
  end
end

def retry_request?(req, err, res, attempt)
  if options[:should_retry]
    options[:should_retry].call(req, err, res, attempt)
  elsif err
    options[:exceptions].any? {|err_class| err.is_a?(err_class) }
  else
    options[:retry_statuses].cover?(req.status)
  end
end

Would you prefer this?

Bertg commented 4 years ago

Made some updates!

Bertg commented 4 years ago

Anything I can do to help progress this PR towards merging?

rkhapre commented 4 years ago

This is available now in Pre 5.x releases?

yashtewari commented 3 years ago

Any updates on this? @ixti are you still in favor of adding retry functionality to Http?

tarcieri commented 3 years ago

The 5.x release is out. If you are still interested in pursuing this, can you rebase?

czj commented 1 year ago

I would still love to get this PR merged :-) Is there any way we could help @levups ?

ixti commented 1 year ago

I can try to take a look on this next week.

czj commented 1 year ago

That's very kind @ixti ! Thank you.

tomprats commented 11 months ago

Would love to have this. I looked into major changes since it's release and besides the hashrocket one, I don't think anything changed to break this.

@ixti would you mind taking a look again?

If you want, I can rebase, but I think if I do it, it'd have to go into a new PR

ixti commented 10 months ago

Sorry been swamped with lots of stuff. Will take a look at the rebased PR as soon as possible. And hope to make it land this month :D

danielb2 commented 5 months ago

@ixti any progress?

wilsonsilva commented 5 months ago

This is neat! I would love to get this out of the box.

tarcieri commented 5 months ago

I would be okay with merging this if someone fixed the merge conflicts

tomprats commented 5 months ago

@tarcieri I fixed it on https://github.com/httprb/http/pull/775

tarcieri commented 5 months ago

Oh hey, sorry about that. Will take a look soon.

tarcieri commented 4 months ago

Merged in #775

Bertg commented 4 months ago

Hurray!

It took 1608 days to get the original work by @ixti to make it in. Not the fastest PR to ever get merged, but glad it did and to be a part of it :)