26
27

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

retryable gemでretry回数を指定したrescueを簡単に

Last updated at Posted at 2014-05-25

(旧タイトル:rescue節での上限回数付きretry(retryカウンタをbegin以前に宣言せずに))
#便利なGemをご紹介頂きました。
もともとの記事のコメント欄で @pasela さんに

retryableというgemを使うとスッキリ書けると思います。

とご紹介頂きました。
ソースが短いので、読んで使い方をまとめてみました(間違っていたらご指摘ください)。
大元の記事はオマケに成り下がりましたw
#retryableの使い方(v1.3.5)
注:v2.0.0以上からメソッドが Kernel.#retryable から Retryable.retryable に変更されました。以下の記載はv1.3.5時点の記事なので読み替えてください。
require 'retryable'します。
Kernel.#retryableに渡すブロックで、例外時にretryする処理を指定します。
具体例は @pasela さんが書いてくださったコメント欄や、retryableのRubyDoc
をご覧ください。
##Kernel.#retryableの仮引数Hash
###繰り返し回数指定::tries
デフォルト値 n=2 。

Should an exception occur, it'll retry for (n-1) times.

###スリープ秒数::sleep
デフォルト値 1秒。
引数には数字またはProcオブジェクトが取れます。

retryable(:sleep => lambda { |n| 4**n }) { } # sleep 1, 4, 16, etc. each try

###捕捉する例外を指定::onまたは:matching
大まかに:onで捕捉する例外を指定して:matchingの正規表現で実際に例外捕捉するようです。
:matchingを指定しなければ:onを満たす例外が捕捉されます。
:onを指定しなければ、:onのデフォルト値StandardErrorに含まれた例外のうち:matchingを満たす例外が捕捉されます。
###例外捕捉時処理の指定::exception_cb
Procオブジェクトで渡します。引数には例外名が渡されます。
###後処理の指定::ensure
Procオブジェクトで渡します。引数にはリトライ回数が渡されます。
###ログ出力指定::task
:taskに処理名称を入れると、名称・リトライ回数・捕捉された例外名をログで表示します。
これ無くなってます(GithubのREADME.markdownにはまだ残ってますが)。
おそらく、リトライ回数と例外名がKernel.#retryableのブロックパラメータへ渡せるので、ログ書くならご自由に、というような事ではないでしょうか。

retryable do |retries, exception|
puts "try #{retries} failed with exception: #{exception}" if retries > 0
pick_up_soap
end


##関連リンク
* [retryable | RubyGems.org | your community gem host](http://rubygems.org/gems/retryable)
* [File: README — Documentation for retryable](http://rubydoc.info/gems/retryable/)
* ~~[bronson/retryable](https://github.com/bronson/retryable)~~ [nfedyashev/retryable](https://github.com/nfedyashev/retryable)
* [Facebookから社内ADまで、外部サービスと連携するときに知っておくと役に立つライブラリ - よかろうもん!](http://interu.hatenablog.com/entry/20120404/1333546980)

<hr>
以下は元記事です。
#核となる部分
カウンタの初期化と加算とを行う`_retry = (_retry || 0) + 1`というイディオムがポイント。

```ruby
retry_upto = 5 # retry回数の上限

begin
  something_do_with_error()
rescue => e
  #カウンタの初期化、加算、上限確認
  if _retry = (_retry || 0) + 1 and _retry < retry_upto
    retry
  else
    #カウンタを念のためにリセット
    _retry = nil
    raise e
  end
end

#具体例
あまり上手い例ではないですスミマセン。

retry_upto = 5

test = lambda {
  loop do
    begin
      print (r = rand(10))
      #rが0..6ならばraise、7..9ならばputs r
      if r <= 6
        raise 
      else
        puts
      end
    rescue => e
      print " -> retry: "
      if _retry = (_retry || 0) + 1 and _retry < retry_upto
        puts _retry
        retry
      else
        _retry = nil
        raise e
      end
    end
  end
}

##実行結果例

> test.call
6 -> retry: 1
6 -> retry: 2
5 -> retry: 3
9
4 -> retry: 4
5 -> retry: RuntimeError: 

> test.call
0 -> retry: 1
1 -> retry: 2
4 -> retry: 3
1 -> retry: 4
2 -> retry: RuntimeError: 

> test.call
7
0 -> retry: 1
5 -> retry: 2
4 -> retry: 3
8
0 -> retry: 4
9
3 -> retry: RuntimeError: 

#参考
本質的にこれをそのまま利用しています。
このやり方うまいなーと思いつつ、そのままブラウザのタブに残してたままにしてました。
そろそろタブを消したいのでQiitaにメモ書きしましたw

begin
@browser = Watir::Browser.new :phantomjs, :http_client => client
rescue Selenium::WebDriver::Error::WebDriverError => e
sleep 0.3
if _r = (_r || 0) + 1 and _r < 5
retry
else
raise e
end
end

[can't create browser object for phantomjs · Issue #222 · watir/watir-webdriver](https://github.com/watir/watir-webdriver/issues/222#issuecomment-27783207)

##以前書いた関連Qiita投稿
[Ruby - rescue 節で一定回数 retry したあとは次に移るループ - Qiita](http://qiita.com/riocampos/items/0870f1b682a62d6477de)
これを書いたあとに上記の書き方を知りました。
26
27
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
27

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?