Requests: max-retries-超過した例外は混乱を招きます

作成日 2013年02月15日  ·  39コメント  ·  ソース: psf/requests

やあ、
例えば:

>>> requests.get('http://localhost:1111')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "requests/api.py", line 55, in get
    return request('get', url, **kwargs)
  File "requests/api.py", line 44, in request
    return session.request(method=method, url=url, **kwargs)
  File "requests/sessions.py", line 312, in request
    resp = self.send(prep, **send_kwargs)
  File "requests/sessions.py", line 413, in send
    r = adapter.send(request, **kwargs)
  File "requests/adapters.py", line 223, in send
    raise ConnectionError(e)
requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=1111): Max retries exceeded with url: / (Caused by <class 'socket.error'>: [Errno 61] Connection refused)

(ポート1111で何もリッスンしていないと仮定)

例外は「最大再試行回数を超えました」と表示されます。 再試行関連のパラメータを指定しなかったため、これは混乱を招きました。 実際、再試行回数の指定に関するドキュメントが見つかりません。 コードを調べた後、urllib3が基になるトランスポートであるように見え、max_retries = 0で呼び出されます(したがって、実際には再試行はありません)。 リクエストは単に例外をラップします。 理解できますが、エンドユーザー(エンド開発者)を混乱させますか? 特にこのエラーが発生しやすいことを考えると、ここでもっと良いことをする必要があると思います。

Feature Request

最も参考になるコメント

私はこれがかなり混乱していることに同意します。 リクエストは再試行しないため(urllib3のHTTPConnectionPoolに対してretries = 0を設定します)、HTTPConnectionPool / MaxRetryErrorのものがないとエラーははるかに明白になります。 リクエストがurllib3を使用していることに気づかなかったのは、両方のライブラリのソースコードを調べて、再試行回数を把握する必要があったときです。

ConnectionError(MaxRetryError("HTTPSConnectionPool(host='api.venere.com', port=443): \
    Max retries exceeded with url: /xhi-1.0/services/XHI_HotelAvail.json (\
    Caused by <class 'socket.error'>: [Errno 10054] \
    An existing connection was forcibly closed by the remote host)",),)

理想的には、例外は次のようになります。

ConnectionError(<class 'socket.error'>: [Errno 10054] \
    An existing connection was forcibly closed by the remote host))

全てのコメント39件

リクエストは、ユーザーの便宜のために例外をラップします。 トレースバックは誤解を招く可能性がありますが、元の例外はメッセージの一部です。 これを改善する方法を考えます。

いくつかのエラーを無視するには、自動再試行が必要だと思います

私はこれがかなり混乱していることに同意します。 リクエストは再試行しないため(urllib3のHTTPConnectionPoolに対してretries = 0を設定します)、HTTPConnectionPool / MaxRetryErrorのものがないとエラーははるかに明白になります。 リクエストがurllib3を使用していることに気づかなかったのは、両方のライブラリのソースコードを調べて、再試行回数を把握する必要があったときです。

ConnectionError(MaxRetryError("HTTPSConnectionPool(host='api.venere.com', port=443): \
    Max retries exceeded with url: /xhi-1.0/services/XHI_HotelAvail.json (\
    Caused by <class 'socket.error'>: [Errno 10054] \
    An existing connection was forcibly closed by the remote host)",),)

理想的には、例外は次のようになります。

ConnectionError(<class 'socket.error'>: [Errno 10054] \
    An existing connection was forcibly closed by the remote host))

それが理想的です。 問題は、私たちと同じようにこれらの例外をラップすることです。 これらは優れたAPIになりますが、デバッグエクスペリエンスは低くなります。 私はそれを修正してすべての情報を保存する方法についてのアイデアを持っています

また、ユーザーが再試行を構成する場合も考慮する必要があります。この場合、この例外が適切です。

@Lukasa 、それを考慮する必要があるかどうかは-Kennethここで、リクエストはAPIの一部として再試行を明示的にサポートすべきではないと述べ

そうですが、ユーザーが実際にそうするのを防ぐ方法はありません。

私の計画は、記録として、最低レベルの例外まで可能な限り下にトラバースし、代わりにそれを使用することです。 @benhoytの例の問題は、ソケットエラー例外が利用できないように見えることです。 (彼が貼り付けたものを見るだけです。私はまだそれを再現して遊んでみませんでした。)

@gaborの例では、実際にこれを簡単に再現できます。 発生した例外をキャッチして、私は次のことを行いました。

>>> e
ConnectionError(MaxRetryError("HTTPConnectionPool(host='localhost', port=1111): Max retries exceeded with url: / (Caused by <class 'socket.error'>: [Errno 111] Connection refused)",),)
>>> e.args
(MaxRetryError("HTTPConnectionPool(host='localhost', port=1111): Max retries exceeded with url: / (Caused by <class 'socket.error'>: [Errno 111] Connection refused)",),)
>>> e.args[0].args
("HTTPConnectionPool(host='localhost', port=1111): Max retries exceeded with url: / (Caused by <class 'socket.error'>: [Errno 111] Connection refused)",)
>>> e.args[0].args[0]
"HTTPConnectionPool(host='localhost', port=1111): Max retries exceeded with url: / (Caused by <class 'socket.error'>: [Errno 111] Connection refused)"
>>> isinstance(e.args[0].args[0], str)
True

したがって、私たちができる最善のことは、 e.args[0].args[0]格納されているメッセージのみを使用することです。これも混乱を招く可能性がありますが、 @ benhoytが遭遇した

@ sigmavirus24 、例外での文字列解析はひどい考えであることに同意します。 ただし、urllib3のMaxRetryErrorは、基になる例外を含むreason属性をすでに公開しています(ソースコードを参照)。 したがって、 e.args[0].reason必要なものを入手できます。

したがって、上記の例を続けると、 e.args[0].reasonsocket.errorインスタンスです:

>>> requests.get('http://localhost:1111')
Traceback (most recent call last):
  ...
requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=1111): Max retries exceeded with url: / (Caused by <class 'socket.error'>: [Errno 10061] No connection could be made because the target machine actively refused it)
>>> e = sys.last_value
>>> e
ConnectionError(MaxRetryError("HTTPConnectionPool(host='localhost', port=1111): Max retries exceeded with url: / (Caused by <class 'socket.error'>: [Errno 10061] No connection could be made because the target machine actively refused it)",),)
>>> e.args[0]
MaxRetryError("HTTPConnectionPool(host='localhost', port=1111): Max retries exceeded with url: / (Caused by <class 'socket.error'>: [Errno 10061] No connection could be made because the target machine actively refused it)",)
>>> e.args[0].reason
error(10061, 'No connection could be made because the target machine actively refused it')

ナイスキャッチ@benhoyt。 私はurllib3にあまり詳しくありません。

あなたが示したようにそれが本当に見えるならば、すなわち。
requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=1111): Max retries exceeded with url: / (Caused by <class 'socket.error'>: [Errno 61] Connection refused)

それから私は本当にもっと良い例外を夢見ることができませんでした。

@ piotr-dobrogost、(私にとっての)主な問題は、再試行がまったく含まれていないときに、「最大再試行回数を超えた」という事実でした。 最初は使っていたウェブサービスだと思って連絡しました。 次に、さらに掘り下げてみると、これがurllib3の癖であることがわかりました。 だからあなたは混乱を見ることができます。

例外の(Caused by <class 'socket.error'>: [Errno 61] Connection refused)部分を見逃しましたか?

ええ、あなたは正しいです-それはすべてそこにあります。 しかし、私が述べたように、MaxRetryErrorは赤いニシンであるため、最初はそれを見逃しました。

この最大再試行のことは常に私を怒らせます。 私が飛び込んで、再試行メッセージを押しつぶすためにPRをまとめることができないかどうかを確認しても、誰か気になりますか?

どこからともなく現れるつもりはありませんが、Cloudantで行っているPythonの作業ではリクエストトンを使用しています。 再試行を含むページが表示されますが、これは赤いニシンである可能性があります。

答えは_多分_です。

問題は、デフォルトでは再試行を実行しませんが、失敗した要求を自動的に再試行するように要求を構成できることです。 そのような状況では、私たちがラップしたMaxRetryErrorは完全に合理的です。 あるべきときにMaxRetryErrorをそのままにして、再試行が行われていないことを保証できるときにそれを削除するソリューションを思い付くことができれば、それを検討します。 =)

@Lukasaありがとう、私はここのバックログで自分自身をリフレッシュしています。 飛び込む機会があれば必ず連絡します。

変更の適切な場所がurllib3にあるように私にはほとんど思えますか? MaxRetryErrorは、自動再試行のコンテキストで発生させるのが理にかなっていますが、再試行がゼロの場合(おそらく単純な要求の経験)、混乱する可能性があります。

urllib3では、紛らわしいエラーがリクエストを介してここでトリガーさretries==0 and max_retries!=0場合にのみMaxRetryErrorを発生させるのがほぼ良いでしょう。 代わりにmax_retries==0を発生させると、代わりにプレーンなRequestErrorが発生しました。

リクエストで使用されるurllib3が含まれているパッケージに存在しているのがわかり

修正がurllib3に属するかどうかは、完全に@shazowにかかっています。 urllib3がデフォルトで再試行(IIRCの3回)することを考えると、彼はurllib3の動作をそのままにしておきたいのかもしれません。 彼の入力を得るために彼にpingを送信します。

いくつかの依存関係の問題を回避するために、urllib3をベンダーに提供しています。 基本的に、これは、既知のバージョンのurllib3に対して常に操作していることを意味します。 ざらざらした詳細が必要な場合、これは#1384と#1812で途方もない長さで議論されています。

ざらざらしているが有益です。 @shazowこれらは私が持っていたほんの少しの考えです-上記のようにMaxRetryErrorではなくRequestErrorを発生させます。 本当に私は私が良く、チェックアウト後MaxRetryErrorを理解すると思いますurlopen

二重編集:実際にはクワーグだけでも、 raise MaxRetryError(retries=0)を使用して、 retries==0メッセージを変更できます。

どの程度retries=False完全に再試行を無効にし、常に代わりに、元の例外を発生させることになるMaxRetryError

urlopenに再試行なしを要求することと、再試行回数を0までカウントダウンすることを区別できると便利です。 再試行を要求しなかったときにMaxRetryErrorが表示されるのは不快です。

誰かがこれのためにパッチ+テストをしたいなら、それはありがたいです。 :)

@shazow素晴らしい、私はサイクルを見つけることができれば私はゲームになるでしょう。 何かあればpingします。

\ O /

^パッチがリリースされているかどうか疑問に思いましたか? この問題は1年前のようです。

私の知る限りではありません。 =)

retries=Falseは、v1.9の時点で元の例外を発生させる必要があり、折り返しはありません。

@kevinburkeの考え?

もう少し時間が必要です

ケビン・バーク
電話番号:925.271.7005 | 20milliseconds.com

10:37の日、2014年10月5日には、イアンCordasco [email protected]
書きました:

@kevinburke https://github.com/kevinburkeの考え?


このメールに直接返信するか、GitHubで表示してください
https://github.com/kennethreitz/requests/issues/1198#issuecomment -57945403

ええ、これは修正されたと思います

requests.get('http://localhost:11211')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "requests/api.py", line 60, in get
    return request('get', url, **kwargs)
  File "requests/api.py", line 49, in request
    return session.request(method=method, url=url, **kwargs)
  File "requests/sessions.py", line 457, in request
    resp = self.send(prep, **send_kwargs)
  File "requests/sessions.py", line 569, in send
    r = adapter.send(request, **kwargs)
  File "requests/adapters.py", line 407, in send
    raise ConnectionError(err, request=request)
requests.exceptions.ConnectionError: ('Connection aborted.', error(61, 'Connection refused'))

私の側で接続拒否の問題が発生しすぎているため、これがどのように解決されたかを教えてください。 私のPythonスクリプトで、RPCサーバーに接続しようとしています

@SiddheshSこの問題は、いくつかの例外を言い換えることで修正されました。実際の接続拒否エラーとは関係ありません。 問題のヘルプを求めるには、 StackOverflowの使用を検討する必要があります。

同じ問題が発生しました。 それは時々起こりました。 修正方法、誰かが私を助けることができますか? 。ありがとう。

requests.exceptions.ConnectionError:HTTPSConnectionPool(host = 'api.xxxx.com'、port = 443):URLで最大再試行回数を超えました:/ v2 / goods /?category = 0&sort_type = 2&page_size = 3&page_num = 13&t = 0&count = 110(原因NewConnectionError( ':新しい接続の確立に失敗しました:[Errno110]接続がタイムアウトしました '、))
トレースバック(最後の最後の呼び出し):
ファイル "test.py"、行335、
主要()
ファイル "test.py"、行290、メイン
結果= get_goods_info()
get_goods_infoのファイル「test.py」、67行目
結果= requests.get(url)
ファイル "/usr/local/lib/python2.7/site-packages/requests/api.py"、69行目、get
return request( 'get'、url、params = params、* _kwargs)
ファイル "/usr/local/lib/python2.7/site-packages/requests/api.py"、50行目、リクエスト
response = session.request(method = method、url = url、* _kwargs)
ファイル "/usr/local/lib/python2.7/site-packages/requests/sessions.py"、行468、リクエスト
resp = self.send(prep、* _send_kwargs)
ファイル "/usr/local/lib/python2.7/site-packages/requests/sessions.py"、行576、送信
r = adapter.send(request、* _kwargs)
ファイル "/usr/local/lib/python2.7/site-packages/requests/adapters.py"、行423、送信
ConnectionError(e、request = request)を発生させます

@nkjulia接続の試行がタイムアウトしています。これは、リモートサーバーが過負荷であるか、接続タイムアウトが低すぎることを示しています。

私もこれで見当違いです…。

@kevinburke接続拒否エラーが発生した後、問題はどのように解決されましたか? バディにアドバイスをお願いします。 TIA

私のポストメイトを無視します。 マシンに複数のバージョンのpythonがあったため、正しいものを選択できず、エラーがスローされていました。 この考えを投稿すると、誰かに役立つかもしれません。

同じ問題が発生しました。 それは時々起こりました。 修正方法、誰かが私を助けることができますか? 。ありがとう。

requests.exceptions.ConnectionError:HTTPSConnectionPool(host = 'api.xxxx.com'、port = 443):URLで最大再試行回数を超えました:/ v2 / goods /?category = 0&sort_type = 2&page_size = 3&page_num = 13&t = 0&count = 110(原因NewConnectionError( ':新しい接続の確立に失敗しました:[Errno110]接続がタイムアウトしました '、))
トレースバック(最後の最後の呼び出し):
ファイル "test.py"、行335、
主要()
ファイル "test.py"、行290、メイン
結果= get_goods_info()
get_goods_infoのファイル「test.py」、67行目
結果= requests.get(url)
ファイル "/usr/local/lib/python2.7/site-packages/requests/api.py"、69行目、get
return request( 'get'、url、params = params、* _kwargs)
ファイル "/usr/local/lib/python2.7/site-packages/requests/api.py"、50行目、リクエスト
response = session.request(method = method、url = url、* _kwargs)
ファイル "/usr/local/lib/python2.7/site-packages/requests/sessions.py"、行468、リクエスト
resp = self.send(prep、* _send_kwargs)
ファイル "/usr/local/lib/python2.7/site-packages/requests/sessions.py"、行576、送信
r = adapter.send(request、* _kwargs)
ファイル "/usr/local/lib/python2.7/site-packages/requests/adapters.py"、行423、送信
ConnectionError(e、request = request)を発生させます

この問題が解決した場合は、アドバイスをお願いします。

このページは役に立ちましたか?
0 / 5 - 0 評価

関連する問題

avinassh picture avinassh  ·  4コメント

8key picture 8key  ·  3コメント

ReimarBauer picture ReimarBauer  ·  4コメント

cnicodeme picture cnicodeme  ·  3コメント

remram44 picture remram44  ·  4コメント