0

We currently use HTTParty gem for our RestClient class in our Rails Engine. Recently, we leveraged the persistent_httparty wrapper to add the ability to set read timeouts and open timeouts. This allows us to then implement our own custom handling for long API calls.

Our code looks like this for RestClient class:

require 'httparty'
require 'persistent_httparty'

module ScheduleEngine
  class RestClient
    include HTTParty

    pool_size = 10
    idle_timeout = 10
    keep_alive = 10
    read_timeout = 3
    open_timeout = 3

    persistent_connection_adapter(pool_size: pool_size, idle_timeout: idle_timeout, keep_alive: keep_alive,
                                  read_timeout: read_timeout, open_timeout: open_timeout)

    class << self
      # other stuff
    end

    # other code omitted for brevity
  end
end

Then, to use this RestClient, we simply instantiate the RestClient where ever we need to make an API call.

client = RestClient.new(user, params)

data = client.callAPI()

Now we want some specific API calls to not have a read timeout or an open timeout.

I'm no Ruby expert but my initial idea is to create a new class which inherits from RestClient class. But this one would simply overwrite some of the base values. Below is an example:

module ScheduleEngine
  class SpecialRestClient < RestClient
    pool_size = 10
    idle_timeout = 10
    keep_alive = 10

    # Note that I'm no longer providing read_timout or open_timeout
    persistent_connection_adapter(pool_size: pool_size, idle_timeout: idle_timeout, keep_alive: keep_alive)
  end
end

With this new class, I can simply instantiate it in places where I don't want a read timeout or an open timeout.

My question is, is this a good approach? Or is there an even better approach?

Update: Here is my 2nd attempt. Looking at the documentation for persistent_httparty, especially around the ConnectionAdapter class, looks like I can pass in a key called timeout and if I provide that, it will overwrite the existing values for read_timeout and open_timeout. My new code looks like this:

module ScheduleEngine
  class SpecialRestClient < RestClient
    persistent_connection_adapter(timeout: 90)
  end
end

I tried that and it didn't work. This makes me think that the method persistent_connection_adapter is supposed to be invoked only once in the beginning and once that's set, you can't change any of the settings.

SpartaSixZero
  • 2,183
  • 5
  • 27
  • 46

2 Answers2

1

Given the way HTTParty works I am unsure what you are suggesting is going to work. It seems like, from a breif run through of the code base, by calling read_timeout, open_timeout, etc. you are setting default options then when you pass options to
persistent_connection_adapter these are just being merged into the "default_options"

This means even though you removed the method calls to read_timeout and open_timeout from the new class chances are they will still trickle down through inheritance.

It might make more sense to configure just the default options and then pass the variable options to persistent_connection_adapter For Example:

 class RestClient
   include HTTParty
   pool_size = 10
   idle_timeout = 10
   keep_alive = 10
   persistent_connection_adapter(read_timeout: 3, open_timeout: 3)
end 

This means you can inherit while still configuring the connection options for this specific class:

 class SpecialRestClient < RestClient
   persistent_connection_adapter
 end 
engineersmnky
  • 25,495
  • 2
  • 36
  • 52
  • Thanks! I'll give that a try. – SpartaSixZero Oct 10 '19 at 13:13
  • 1
    @SpartaSixZero "didn't work" is not very descriptive. However after reviewing the code in `persistent_httparty` it seems that thier mechanism does not respect any `HTTParty` default options so you would need to set the values every time you call. `persistent_connection_adapter` or for each request individually. Additionally that gem was written and has not been updated in 7 years (might want to look for a different persistent adapter that has remained in line with any change HTTParty has made) – engineersmnky Oct 10 '19 at 16:51
0

what about adding initializer here, which will take timeouts hash? like:

def initialize(timeouts = {})
@timeouts = timeouts
end

def call
persistent_connection_adapter({pool_size: 10, idle_timeout: 10, keep_alive: 10}.merge(timeouts))
end

private attr_reader :timeouts

so if you would like to set timeouts you just define while initializing.

call is just a function to call after initialization

DynoMike
  • 49
  • 4