Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to use retry with POST method #780

Closed
yusefu opened this issue Mar 12, 2018 · 3 comments
Closed

How to use retry with POST method #780

yusefu opened this issue Mar 12, 2018 · 3 comments

Comments

@yusefu
Copy link

yusefu commented Mar 12, 2018

Basic Info

  • Faraday Version:
    faraday (0.11.0)
    faraday_middleware (0.11.0.1)
    faraday_middleware-aws-signers-v4 (0.1.5)

  • Ruby Version:
    ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-darwin15]

Issue description

I have an interface accessing some api, was using a Faraday connection with get method and setting a retry, and everything was working fine until I changed my method to post then the retry stopped working I googled a bit so I understood that the post is not included in the

IDEMPOTENT_METHODS = [:delete, :get, :head, :options, :put]

ref: https://github.com/lostisland/faraday/pull/437/files
and I have to use retry_if if I would like to retry the POST but didn't find a documentation dor retry_if.

So my connection looks like this:

    def my_connection(my_api_endpoint)
      Faraday.new(url: my_api_endpoint) do |faraday|
        faraday.request  :retry, max: 5, exceptions:
          [BadRequest, NotFound, ServerError, Faraday::Error::ConnectionFailed]
         faraday.response :logger
         faraday.adapter  Faraday.default_adapter
         faraday.options[:open_timeout] = 10
      end
    end

and calling it this way:

  res = my_connection(my_api_endpoint).post do |req|
    req.headers['Content-Type'] = 'application/json'
    req.options.timeout = 25
    req.body = body.to_json
  end

Any help will be very welcome.

@iMacTia
Copy link
Member

iMacTia commented Mar 12, 2018

Hi @yusefu, apologies for the lack of documentation, this is something we're trying to address in v1.0.
In the meantime, let me help with your issue. Basically the retry_if is an option you can pass exactly how you pass max: 5, exceptions: [BadRequest, NotFound, ServerError, Faraday::Error::ConnectionFailed]. The only difference is that retry_if must be a function (either a lambda or a proc.
If you're unfamiliar with those, I would suggest to go with a proc, which can be instantiated with Proc.new { ... } or with the multi-line Proc.new do ... end.

So if you want to use retry_if your example would become something like:

def my_connection(my_api_endpoint)
  # This is optional, I've added the @connections memoized variable to avoid
  # re-creating the connection every time. Not sure it's applicable to your case
  # but consider it as it might improve performances
  @connections ||= []
  @connections[my_api_endpoint] ||= Faraday.new(url: my_api_endpoint) do |faraday|
    faraday.request  :retry, max: 5, exceptions:
      [BadRequest, NotFound, ServerError, Faraday::Error::ConnectionFailed],
      retry_if: Proc.new do |env, exception|
        # your implementation goes here...
      end
     faraday.response :logger
     faraday.adapter  Faraday.default_adapter
     faraday.options[:open_timeout] = 10
  end
end

However, if your only aim is to add :post to the list of retry methods, you can also use the methods option added on that PR you linked:

def my_connection(my_api_endpoint)
  # This is optional, I've added the @connections memoized variable to avoid
  # re-creating the connection every time. Not sure it's applicable to your case
  # but consider it as it might improve performances
  @connections ||= []
  @connections[my_api_endpoint] ||= Faraday.new(url: my_api_endpoint) do |faraday|
    faraday.request  :retry, max: 5, exceptions:
      [BadRequest, NotFound, ServerError, Faraday::Error::ConnectionFailed],
      methods: Faraday::Request::Retry::IDEMPOTENT_METHODS + [:post]
     faraday.response :logger
     faraday.adapter  Faraday.default_adapter
     faraday.options[:open_timeout] = 10
  end
end

Please let me know if this helps 😄

@yusefu
Copy link
Author

yusefu commented Mar 13, 2018

The connections instance gave a TypeError.

expected MyAPI::BadRequest, got #<TypeError: {:req=>{}, :res=>nil, :headers=>nil, :reason_phrase=>nil}> with backtrace:

But with the simple add of post to IDEMPOTENT_METHODS the retry is now possible.
Thank you very much @iMacTia 🙏 it did work.

@yusefu yusefu closed this as completed Mar 13, 2018
@iMacTia
Copy link
Member

iMacTia commented Mar 13, 2018

Thanks for the feedback @yusefu and sorry for the TypeError.
I think the issue is that @connections should be a hash, not an array, my bad!

@connections ||= {}

Anyway, happy to know your issue is now solved 👍!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants