1

I've been struggling with Faraday and my Ruby on Rails app. An API controller in Rails creates a Model instance and sends this data serialized in JSON to an external app that will process the data and send a response with float number inside its response within a few seconds of the request.

However, my app sometimes sends 50 individual requests and the external app may return a 502 error string as a response (please notice not an actual 502 HTTP error!!!). I tried throttling my Faraday calls, but that made the external app go berserk, so now I'm trying to figure out how to re-submit a request if the response throws out this 502 string. I haven't figured out how to write a Middleware for this, but it has not been necessary for now.

Is there a way I can tell my method to resubmit the request to the external app if it receives a certain response inside its body?

Here is my code (this method gets triggered for every request):

Controller

  def create
    cl = Model.where(
      attr1_id: params[:attr1_id],
      attr2_id: params[:attr2_id]
    ).first_or_initialize(params)
    cl.update(params)

    # Send new Model data (in JSON) in a request to external app
    cl_r = cl[:attr1_id]
    r = Some_model.find_by(id: cl_r)
    request = { :cl => cl, :r => r }

    # Send the request
    response = @conn.post do |req|
      req.url '/ml'
      req.headers['Content-Type'] = 'application/json'
      req.headers['password'] = 'password'
      req.body = request.to_json
    end

    # Get the response
    response_json = response.body
    response_json = response_json.gsub(/\s+/m, ' ').strip.split(" ")[1]

    # If the response (which takes a few seconds) returns a float inside its response body
    cl.update_attributes(response_attribute: response_json)
    # Else
    # Send the request that returned a 502 string inside the body to the external app again
    # End

    respond_with cl
  end

Thanks, your help is very appreciated!

Community
  • 1
  • 1
Doge
  • 315
  • 1
  • 8
  • 26
  • have you tried checking the documentation for retry? http://www.rubydoc.info/github/lostisland/faraday/Faraday/Request/Retry – Maru Oct 19 '17 at 11:17
  • @Maru , my request does not fail, hence why retry won't trigger. The response has a 502 in it's body, but not in the HTTP header – Doge Oct 19 '17 at 11:32
  • why not force it to fail when you get a 502? raise a custom exception when you get 502. you can trigger retry on custom exceptions – Maru Oct 19 '17 at 11:33
  • @Maru the documentation is practically non-existant, how would I achieve that with the code I have given on this thread? – Doge Oct 19 '17 at 11:38

2 Answers2

4

You can try the code below

Faraday.new(your @conn params here if any) do |conn|
  conn.request :retry, max: 2, interval: 0.05,
                       interval_randomness: 0.5, backoff_factor: 2,
                       exceptions: [CustomException, 'Timeout::Error']

  response = conn.post do |req|
      req.url '/ml'
      req.headers['Content-Type'] = 'application/json'
      req.headers['password'] = 'password'
      req.body = request.to_json
    end

  raise CustomException if response.status == 502


  ...
end

you can check out the documentation for additional information.

Lev Lukomsky
  • 6,346
  • 4
  • 34
  • 24
Maru
  • 590
  • 5
  • 14
  • 1
    How to test this? Say I had a generic HTTP client which used Faraday, is there a recommended way to test this sort of functionality? – MrMesees Jan 28 '19 at 09:06
0

you can add

builder.response :raise_error

to your connection builder to automatically have Faraday raise ClientError if the request is not successful (based on the response code, e.g on 4xx/5xx codes).

You also have to add Faraday::Error to your exceptions array in the retry config