本日、Uber Eatsで大規模障害がありました。React Native絡みのようなので、今わかっている範囲の事実だけメモしておこうと思います。
公式アナウンス
【システム障害に関するお知らせ】
— Uber Eats Japan(ウーバーイーツ) (@UberEats_JP) 2020年1月16日
現在、Uber Eatsアプリのシステム障害の為、サービスを一時停止しております。
ご迷惑をおかけしますが、復旧までしばらくお待ちください。
【サービス再開のお知らせ】
— Uber Eats Japan(ウーバーイーツ) (@UberEats_JP) 2020年1月16日
サービスを再開いたしました。
ご注文に影響のあった注文者の皆様には個別にメールにてご連絡致します。
Uber Eats は、今後同様のケースが発生しないよう再発防止に努めてまいります。
今後ともよろしくお願い申し上げます。
ユーザーの声
Twitterを眺めている限りでは、店舗側に配布されているアプリ(レストランアプリ)が利用できなくなり、受注の確認ができなくなっていたようです。
Open!!!!
— NU BURRITOS (@NuBurritos) 2020年1月16日
Uber eatsの端末不具合で現在注文を受ける事ができません!!!
いつ復活するかわ未定だそうです!!!
ご迷惑をお掛けします🙇♂️#simokitazawa #UberEats #burrito pic.twitter.com/ff9Lr7C6Rm
店 Uberタブレット死亡
— ぱす!@うーばーいーつ配達員兼レストランパートナー (@Ubereat56077235) 2020年1月16日
Uber eatsアプリでは注文可能
この後の展開は配達員が店にきて受注発覚。
配達員アプリから注文品が分かり作り始められる。
配達員よ。すまんが無理や。
店もどうしようもない😊 pic.twitter.com/nXeIBRknFy
現在、Uber Eats端末に障害が発生しております。ご迷惑をおかけしておりますが、復旧までしばらくお待ち下さい。 pic.twitter.com/Iwj0cE13da
— 喫茶ルプラ|Lupra's Roasting Factory & café (@kaffee_haus) 2020年1月16日
今度はお店端末が
— あるば🔰@UberEATS東京🐸 (@alba_UberEATS) 2020年1月16日
オンラインになれない問題🤔
これは大事件の匂いΣ('◉⌓◉’)#UberEats pic.twitter.com/YP8Js5ZZDP
React Nativeっぽい
Uber EatsチームがReact Nativeを採用していることは、次の公式エンジニアブログでも言及されています。
本件で報告が上がっていた赤い画面は、React Nativeのデバッグモードで console.error()
や最上位まで到達してしまった例外の内容を表示するための、RedBoxと呼ばれる開発補助のための機能です。レストランアプリもReact Native製と見て問題ないでしょう。
2つの事実を確認する
それでは、React Nativeの観点で、今回報告されている画面から読み取れる内容について解説します。主に次の2件について言及します。
- RedBoxが表示されている
- Textコンポーネントについてのエラーが出ている
RedBoxが表示されている
まずは、赤い画面(RedBox)が出ている件についてです。繰り返しになりますが、
本件で報告が上がっていた赤い画面は、React Nativeのデバッグモードで
console.error()
や最上位まで到達してしまった例外の内容を表示するための、RedBoxと呼ばれる開発補助のための機能
です。
React Nativeでアプリ開発をしたことがある方なら日常的に目にしているものですが、そうでない方はほぼ見たことないと思います。React Nativeは多くの有名アプリで使われているにもかかわらず、です。
というのも、RedBox(とconsole.warn
を司るYellowBox)はリリース用にビルドした際に無効化され、ストアに公開された時点で表示されなくなっているために、ユーザーとしてアプリを触る場合には目にすることがないからです。
次の公式ドキュメントでも言及されています。
RedBoxes and YellowBoxes are automatically disabled in release (production) builds.
今回の障害では、Uber EatsのレストランアプリにRedBoxが表示されていました。
誤ってなのか、もともとそういう運用なのかはわかりませんが、今回障害のあったレストランアプリはデバッグビルドされたものだったことが見て取れます。
Textコンポーネントについてのエラーが出ている
RedBoxは console.error()
なので、そのとき発生したエラーのメッセージとスタックトレースが表示されています。メッセージの内容を見てみましょう。
Invariant Violation: Text strings must be rendered within a
<Text>
component.
これはブラウザ開発に慣れ親しんだ方がReact Nativeを触り始めたときによくやるエラーで、簡単に再現することができます。↓の "Tap to play" を押すと、実行結果を見ることができます。
今回起きていたのは、JSX内で <Text>
コンポーネント以外の場所に文字列を書くと発生するエラーです。ブラウザなら <div>
の直下にテキストを書いても怒られませんが、React Nativeで <View>
の直下にテキストを書くと怒られるのです。((最終的にAndroidのTextView
やiOSのUIView
に落とし込まないと表示できないと考えると、妥当な仕様です。))
これは静的解析では見つけづらいエラーなので、ちょっと同情はします。しかし、言ってしまえば凡ミスの類いなので、特に今回の障害でReact Nativeのヤバさが露見したとか、そういうことではないように思います。
追記
使ったことなかったけど、eslint-plugin-react-nativeの react-native/no-raw-text
ルールで検出できそう。
感想と邪推
というわけで、Twitterで報告されていた内容から読み取れる範囲の事実について解説しました。ここからは私個人の意見や妄想の話で、事実に基づく話ではないものが混ざっています。眉に唾をつけて読んでください。
デバッグビルドの話はアプリの運用ルールの話なので、良いとも悪いとも断言できない部分もあるのですが、普通はやらないです。というのも、デバッグ中というのは、APKファイルの中にJSファイルを内包するのではなく、パソコン側で立ち上げた開発サーバーからJSファイルを逐次にダウンロードして画面に描画するため、配布に向いていないはずだからです。
……もしかして、開発サーバーを公開サーバーの中で起動しておいて、配布したデバッグビルドのアプリからアクセスさせている……? そうすれば、Hot Reloadの要領で、最新の実装がリアルタイムでエンドユーザーの手元に届くから……? そんなことある……? 簡易Code Pushとして技術的には実現可能かもしれないけど、本当にやるか……?
妄想はできるのですが、憶測を見てきたかのように語るのもよくないので、口を噤むことにしましょう。
追記:Textコンポーネントのエラーが起きるパターン
ちょっとだけ複雑なパターンもあるようです。
推測ですが経験上、 {str && <Component />} みたいに条件分岐書いててstrに空文字が来ると短絡評価されて空文字がrenderされてしまうというパターンな気がしますね〜。
— しんのき (@konoki_nannoki) 2020年1月16日
条件式をちゃんとbooleanにするか三項演算子使うか気をつけないと起こります。 https://t.co/HBextTrA8k
例えば、こんなコンポーネントがあったとします。
type Props = { message: string; }; const Component: React.FC<Props> = ({ message }) => ( <View> {message && <Text>message</Text>} </View> );
これを <Component message="">
のように呼び出した場合、JSX部分の条件式が評価されて次のようになります。
<View> "" </View>
こうなるとViewの直下にテキストがきてしまうので、アウトです。空文字はfalthyなので、短絡評価の結果として左オペランドだけが残った形ですね。Twitterを見ていると、このケースがあるある案件のようです。
とはいえ、想像の域を出ないので、実際にこういう実装をした結果として起きたエラーだというわけではありません。
おわりに
今回の件は、React Native関連の障害としては初めてと言っていいレベルの大規模なものになったように思います。しかしながら、React Nativeのせいというにはちょっと運用のほうが前衛的すぎるんじゃないかなという感想を持ちました。
こんな事例を挙げて、訳知り顔で「これだからReact Nativeみたいなツールは信用できない」みたいなことを言う人が出てくるのも業腹なので、そうではないよ、と言うために筆を取った次第です。
それにしても、本当にどういう運用をしているのか純粋に(割とポジティブな感情で)興味が出てきました。いつかReactConfとかApp.js Confあたりで、今回の障害についてUber Eatsのエンジニアから振り返りセッションがあったりすると面白いのになあ、と思っています。