Ubiregi Advent Calendar 2019 3日目です。
2日目に引き続きフロントエンドエンジニアのコジャが担当します。
今回は簡単にReactでカオスエンジニアリングが体感できるreact-chaos
をやってみます。
カオスエンジニアリングって何?
何でしょう。私も今日に至るまで言葉は知っていましたが、実際に何をするのか、何でするのかはわかりませんでした。
ざっくり調べると「擬似的に障害を起こし、実際の障害にも耐えられるようにする」ことだそうです。
詳細は以下のQiita記事がわかりやすかったです。
react-chaosって?
react-chaosはReactで作られたアプリケーションに対して、意図的にエラーを発生させる
High Order Componentです。
ただ、READMEを見てみると、以下の一文があります。
🛑 Pre-Installation Notes
- This is currently WIP and a proof-of-concept.
- There is nothing in place to help ensure good performance practices. Use at your own risk.
実運用はまだのようですね。
なにはともあれ
やっていきます。
まずは、react-router-domを使用して、簡単なルーティングするようなアプリを作ってみます。
const App = () => {
return (
<BrowserRouter>
<Layout>
<Switch>
<Route exact path='/'><Home /></Route>
<Route path='/about'><About /></Route>
<Route path='/dashboard'><Dashboard /></Route>
</Switch>
</Layout>
</BrowserRouter>
)
}
動きはこんな感じです。
見ての通り、/
がHome、/about
がAbout、/dashboard
がDashboardと表示されます。
では早速、<About />
にreact-chaosを適用してみましょう。
第一引数は適用対象のコンポーネント、第二引数はエラーの発生頻度、第三引数はエラーメッセージになります。
今回エラー発生頻度を10にしたので、/about
にアクセスした時、必ずエラーが発生することになります。
import React from 'react';
import withChaos from 'react-chaos/src/index.tsx';
const About = () => {
return (
<div>
<h2>About</h2>
</div>
);
}
export default withChaos(About, 10, 'カスタムエラーだよ');
yarn start
します。
./node_modules/react-chaos/dist/index.js
Module not found: Can't resolve './chaos-react.cjs.development.js' in '/Users/koja/workspace/react-chaos-example/node_modules/react-chaos/dist'
失敗します。なんでや。
動かないんだ...
まぁまだ慌てる段階ではない。node_modules/react-chaos/dist配下を見てみると、出力エラーの通り、index.jsしか存在しませんでした。へぇ~
リポジトリのissueを漁るとこんなのが。
the newest npm package wrong? #10
This is still an issue.
なるほどね。
npmのレジストリでなく、直接gitのリポジトリを指定してもダメでした。というかbuildがコケてた。
再挑戦
ただ、demoは動いているので以前のバージョンを指定すれば、ビルドできるはずです。
現vは0.1.0でその前のvは1.0.6ってことは破壊的変更があったんでしょうか?まぁあまり気にしないことにします。
yarn add -D react-chaos@1.0.6
yarn start して /about
にアクセスしてみると、画面が真っ白になります。コンソールを開くと舐めたエラーメッセージが出力されています。成功です。
どうやって対処する?
Reactでは予期せぬエラーが発生した時、代わりの画面を表示するError Boundaryなる方法があります。
実装はこんな感じ。
import React, { Component } from 'react'
export default class ErrorBoundary extends Component {
constructor(props) {
super(props)
this.state = { hasError: false }
}
static getDerivedStateFromError(error) {
return { hasError: true }
}
render() {
return this.state.hasError ? <h1>一時的なエラーが発生しています</h1> : this.props.children;
}
}
エラーが発生しうるコンポーネントを子要素に持つようにします。今回は<About />
が対象です。
const App = () => {
return (
<BrowserRouter>
<Layout>
<Switch>
<Route exact path='/'><Home /></Route>
<Route path='/about'>
<ErrorBoundary>
<About />
</ErrorBoundary>
</Route>
<Route path='/dashboard'><Dashboard /></Route>
</Switch>
</Layout>
</BrowserRouter>
)
}
こうすればエラーが発生した時、画面がホワイトアウトするのを防いで、用意したエラーメッセージを表示してくれます。下記のgifではエラーの発生頻度を3まで落としたので、なかなか発生しませんでした。
最後に
実装まで紹介できるかなと思ってたんですが、Errorを発生させる条件が割と複雑だったのでやめました。数学ができない。