Forum: Ruby How to DRY this up?

Posted by tamouse mailing lists (Guest)
on 2013-01-24 18:18
(Received via mailing list)
I have some API calls I'm making, all with the following sort of
begin-rescue-end wrapper:

(pseudo-code)

retries = 0
begin
  response = SomeAPI.api_method1(:request => { 'ThisId' => this_id })
rescue API::Exception => e
  retries.succ
  sleep( retries * 5 )
  retry unless retries > 2
end

where there are multiple api_methods and request forms. Seems like I
should be able to DRY this instead of doing this everywhere I have to
make this sort of API call.
Posted by "Jesús Gabriel y Galán" <jgabrielygalan@gmail.com> (Guest)
on 2013-01-24 18:30
(Received via mailing list)
On Thu, Jan 24, 2013 at 6:18 PM, tamouse mailing lists
<tamouse.lists@gmail.com> wrote:
>   sleep( retries * 5 )
>   retry unless retries > 2
> end
>
> where there are multiple api_methods and request forms. Seems like I
> should be able to DRY this instead of doing this everywhere I have to
> make this sort of API call.

You could create a method for it (untested):

def call_with_retries obj, method, *args, retries=2
  begin
    response = obj.send(method, *args)
  rescue API::Exception => e
    retries -= 1
    sleep( retries * 5 )
    retry unless retries < 0
  end
end

and call it like

call_with_retries SomeApi, :api_method1, :request => { 'ThisId' => 
this_id }

You could also pass the exception to rescue, or just rescue
StandardError, and also pass the time to sleep.
Hope this gives you some ideas.

Jesus.
Posted by Nokan Emiro (Guest)
on 2013-01-24 18:33
(Received via mailing list)
You can create a class that represents the api connection and use
method_missing
to collect all the API calls to one place in your code, like this:

class ApiWrapperClass
  def method_missing(meth, *args)
    retries = 0
    begin
      SomeAPI.send(meth, *args)
    rescue API::Exception
      ...
    end
end

x = ApiWrapperClass.new
x.api_call( .... )



On Thu, Jan 24, 2013 at 6:18 PM, tamouse mailing lists <
Posted by Robert Klemme (robert_k78)
on 2013-01-24 18:55
(Received via mailing list)
On Thu, Jan 24, 2013 at 6:29 PM, Jess Gabriel y Galn
<jgabrielygalan@gmail.com> wrote:
>> rescue API::Exception => e
>>   retries.succ

That #succ won't do anything because the result is not stored.

>>   sleep( retries * 5 )
>>   retry unless retries > 2

You are sleeping too much here because after the last attempt you are
sleeping as well.  Reason is that the decision to retry is made after
sleeping. Grouping that in an if end would be better.

>     response = obj.send(method, *args)
>
> You could also pass the exception to rescue, or just rescue
> StandardError, and also pass the time to sleep.
> Hope this gives you some ideas.

I'd rather put the code to invoke into a block because it gives much
more flexibility and separates concerns:

def retry_code(retries = 2)
  count ||= 0
  yield
rescue API::Exception => e
  count += 1

  if count <= retries
    sleep count * 5
    retry
  end
end

response = retry_code { SomeAPI.api_method1(:request => { 'ThisId' =>
this_id }) }

Kind regards

robert
Posted by tamouse mailing lists (Guest)
on 2013-01-24 22:50
(Received via mailing list)
On Thu, Jan 24, 2013 at 11:55 AM, Robert Klemme
<shortcutter@googlemail.com> wrote:
>>> begin
> sleeping as well.  Reason is that the decision to retry is made after
>> def call_with_retries obj, method, *args, retries=2
>>
>   count ||= 0
> response = retry_code { SomeAPI.api_method1(:request => { 'ThisId' =>
> this_id }) }
>
> Kind regards
>
> robert
>
> --
> remember.guy do |as, often| as.you_can - without end
> http://blog.rubybestpractices.com/
>

Thanks, robert -- I very much like your version.
Posted by tamouse mailing lists (Guest)
on 2013-01-25 00:51
(Received via mailing list)
On Thu, Jan 24, 2013 at 3:47 PM, tamouse mailing lists
<tamouse.lists@gmail.com> wrote:
> On Thu, Jan 24, 2013 at 11:55 AM, Robert Klemme
>> I'd rather put the code to invoke into a block because it gives much
>> more flexibility and separates concerns:

> Thanks, robert -- I very much like your version.

And that's how I ended up writing it. The more I look at this, the
more chuffy it feels. Very awesome! Very ruby! Feels just the best of
OO and Functional rolled together.
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.