Unity2017.3.0p4でLambdaの実行が失敗する原因の調査

ラディアスリーの加藤です。
先日『Unity2017.3.0p4 で AWS SDK が例外を吐くようになったので原因を調べてた』というエントリーを書いたのですが、テストを行ってみるとどうもiOS端末上で lambda の実行が失敗する事に気が付きました。
アプリ起動時にユーザデータの確認のため lambda を叩いてデータを取得するという処理を行っていたので、当初は「起動直後に lambda を叩いた場合 Credential なんかが確定する前に lambda を叩いてしまうケールがあるのかな?」なんてことを考えていました。
成功するケースもあるので、「リトライ処理を組み込めば良いのか?」なんてことも考えたのですが、原因がはっきりとしないまま変なリトライ処理を埋め込むのも気持ちが悪いと思い調査を行ってみました。
結構、軽い気持ちで調査を始めてみたのですが、これが意外と混沌としてしまっていて、思いの外時間を取られてしまったのですが…
まぁ、せっかくなので足跡を残しておこうと思います。
…Webでの情報も少ないので、レアケースなんですかね?

問題

Unity2017.3.0p4 で AWS SDK から Lambda の function を呼び出そうとすると、iOS端末(実機)でエラーが返ってきてしまうことがある。
Unity エディタ上では、現象が再現しない。
返ってくるエラーは以下の内容となっていた。
The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.
Unity Editor 上では状況が再現せずに、正常に lambda の実行が行えている。
iOS端末(iPhone7)では、体感的にだが6〜7割程度の確率でエラーが返ってきているようだ。
(正常に lambda の実行が行えているときもある)

ビルド環境

macOS High Sierra(10.13.3)
Unity2017.3.0p4
AWSSDK.Lambda.3.3.12.0.unitypackage

問題が発生する環境

iPhone7(MNCR2J/A)
iOS 11.2.5

原因?

AWS SDK の内部では UnityWebRequest を利用して通信が行われているが、その際にリクエストヘッダに ”Transfer-Encoding:chunked” が含まれるケースがあり、その時に上記エラーが返ってきてしまうようだ。
前回のポストで、AWS SDK が例外を吐いてしまう問題の対応として、

 

のように UnityWebRequest を利用するように設定を行ったが、ここから今回の問題に派生したようだ。

対応方法

github で公開されている CustomUnityMainThreadDispatcher コンポーネントを採用させてもらった。
次のようなコードを追加した。

 

原因調査の記録

色々とハマったので、以下に原因調査の記録を残しておく。
(単なる備忘録なので、この先には有益な情報は無い。)
うまく lambda が実行できるときと、エラーが返ってしまう時があるので、原因を探りたかったのだがどうにも腑に落ちるような結論が得られずに困った。
エラーメッセージから、Quiitaで公開されていた『Unity2017.3 AWSSDKエラーの回避』のエントリーと、そこで紹介されていた AWSSDK.NET の github issue ( https://github.com/aws/aws-sdk-net/issues/820 ) にたどり着いたのだが、同じエラーが発生しているとは言え、発生確率が異なる(私のケースでは、うまく動くときもある)ので今ひとつ納得感ないのだが、上記対応を入れてみた所エラーが発生しなくなっているようなので、ひとまずはここが問題だったと結論づけておく。
CustomUnityMainThreadDispatcher では、UnityWebRequest の Transfer-Encoding を 無理やり false にすることで回避を行っているようなので、逆に Transfer-Encoding を常に true に設定することでエラーになる場合の再現が行えるかと考えたのだが、うまくいかなかった。(成功する場合も、失敗する場合もある)
件の Quiita エントリーでは、
UnityEditorからUnityWebRequest(AWSSDKを使用せずシンプルなコードで)を使って送信内容を確認してみると、Unity2017.3.0p4にのみTransfer-Encoding: chunkedのHeader情報が追加されていました。
どうやらこの影響で、エラーが発生しているようなのです。
と書かれていたので、エラーになるケースではリクエストヘッダに “Transfer-Encoding:chunked” が含まれており、逆にうまく動作するケースでは含まれていないという仮説を立てて再現を行おうとしたが、AWS SDK を利用している状況でリクエストヘッダを確認する手段がどうにも思いつかなかった。
当初は、 CustomUnityMainThreadDispatcher の内部で、リクエストヘッダの中身を確認できないかとごにょごにょとコードをいじってみたのだが、思ったような成果は得られなかった。
仕方がないので、 UnityWebRequest を使ったシンプルなシーンとリクエストを受け取りヘッダをそのまま返すだけのシンプルなサーバを作成してリクエストヘッダの内容を確認することにした。
サーバは node.js で以下のような簡単な処理を書いた。

 

対するクライアント側は、以下のようなコンポーネントを作成した。
ボタンを押すとリクエストを投げて、結果を画面表示するだけの簡単なものだ。
調べていくとどうも UnityWebRequest で Post する時のデータに応じて、リクエストヘッダに Transfer-Encoding が含まれるのか、含まれないのかが決まるようだ。
これを実行してみると次のような結果が得られた。
Getの場合
Post(データなし)の場合
Post(データ=‘hello’)の場合
Post(データ=’6\nHelloWorld\n5\n 0\n’)の場合
結果から、Post 時に何らかのデータが含まれていると、リクエストヘッダに Transfer-Encoding が含まれることがわかった。
推察するに、AWD SDK が何らかの条件で、Post と Get を使い分けているのか、Post 時にデータを含めたり、含めなかったりしているのではないかと思う。
また、 iOS端末上では問題が発生することがあるがUnityエディタ上からでは問題が発生しないことから、iOS端末での実行とUnityエディタ上での実行で、レスポンスヘッダに変化があるのかと推察していたが、調査を行ってみた所、どちらも同じ条件(Post時になんらかのデータが含まれている場合のみ)で Transfer-Encoding が含まれることがわかった。

まとめ

なんとなく釈然とはしないが、
「iOS端末上でレスポンスヘッダに Transfer-Encoding が含まれている場合にlambda の実行が失敗する」
として、AWS SDK 側で対応が行われるまでの間は、 CustomUnityMainThreadDispatcher を利用させてもらうことにしようと思う。

参考

加藤 貴之 について

代表取締役社長 兼 エンジニア ゲームエンジン開発だとか、OpenGLだとか、3Dプログラミングあたりが自分の専門分野なんじゃなかろうかと思いながらも、Unityでゲームアプリの開発をしています。 社長業よりもゲーム開発関連技術のことを調べている方が好き