謎の ChunkedEngcodingError
Google App Engine Standard Environment (Python 2.7) で line_bot_sdk を使って LINE Bot を動かしていると、ときどき以下のような例外を吐きます。
ChunkedEncodingError: ('Connection broken: IncompleteRead(2 bytes read)', IncompleteRead(2 bytes read))
返答を投げ終わった後のレスポンスのパースで落ちているため、メッセージ送信自体は正常に完了しているので、無視しても良いのですが、どうにも気持ち悪いので、原因を調査してみました。
原因
- GAE では httplib が urlfetch で再実装されている。
- line_bot_sdk が使っている requests が使っている urllib3 には、下位層が httplib のインスタンスだったときだけ http の chunked encoding を自前で解決するコードが含まれている。
- しかし、urlfetch で再実装された GAE の httplib は chunked encoding を自前でデコードしてしまう。
- urllib3 で chunked encoding を二重にデコードしようとして例外が発生する。
エラーの中身
IncompleteRead(2 bytes read) と出ている中身をデバッグ出力してみたところ、 '{}' でした。
LINE Messaging API のサーバは、普段は chunked encoding を使わないのですが、まれに chunked encoding で返信を返してくるようで、その時だけエラーが発生していたようです。
複数端末から同時アクセス発生時にのみ起こる気がしますので、複数リクエストが被ってコネクションをkeepaliveで使いまわした時だけとか、そういう話な気がしてますが、そこまでは追っていません。
解決方法
類似した内容をディスカッションしている urllib3 の issue では、以下のパッチが提案されています。
urllib3 の問題なのに requests のレイヤで対応しているのが微妙に気持ち悪いですが、とりあえず同じパッチを当てれば、chunked encoding の問題は発生しなくなります。
(本質的には、urllib3/response.py で self.raw の httplib の中身が GAE 版だと判別できたら self.chunked を True にしないというのが正しい対処のはずです)