あれ
あれ
「AmplifyのDataStoreやめるかぁ」
→ついでにNext.jsのServer Actionに統一するかぁ
→AmplifyのGraphQLのAPIをいい感じに叩けるようにするかぁ
→ついでにAmplifyJSをv5からv6にバージョン上げるかぁ(互換性なし)
→DataStoreのキャッシュ使わなくなったから画面遷移が遅くなったし、サーバー側で動かせるキャッシュ機構作るかぁ
とかやってたら、これまで作ったシステムの土台部分がほぼ書き換えになった。
あちこちのReact ComponentでDataStoreが使われているのを、いつかDataStoreを辞めようと思って少しずつまとめていたが、それでもかなりの量のコードを書き換えることになった。
AWS Amplifyで検証用アプリを作ったあとに削除したら、大本のアプリのBackend environmentsが意図せず消された
再現手順
Amplifyを触ったことがある人を対象としているため、画像を貼ったりせず、事細かには説明しない。適宜補完してほしい。
本番と見なすAmplifyのアプリを作成する
ダミーのウェブアプリを作る
- Githubに空のレポジトリを作成する
- GithubからレポジトリをCloneする
- ローカルの端末で
npx create-react-app amplify_the_destroyer
などと実行して、テスト用に適当なウェブアプリを作成する。ここでnext.jsで作るとややこしいことになるのでやってはいけない。
Amplifyのウェブコンソールでの作業
- Amplifyのウェブコンソールから「アプリケーションを構築」を押して、アプリ(名前はto_be_destroyedとする)を作成する。
ローカルの端末での作業
- Backend environmentsにstagingがあるので、これを
amplify pull --appId {appId} --envName staging
で取得する。 git add .
、git commit -m "init"
、git push
を実行して、レポジトリにコードを反映させる。
Amplifyのウェブコンソールでの作業
- Hosting environmentsからGithubを選択して、上記レポジトリのmainブランチと連携させる。
- 「ビルドの設定」画面で、Environmentを「新しい環境を作成」にし、Environment名は空欄のままにする。
- デプロイを開始し、デプロイされるのを待つ。
作業結果
下の画像のようになれば成功だ。Amplifyを使っている人には見慣れた光景かと思う。
この後、ローカルの端末でamplify pull --appId {appId} --envName main
を実行してmainと同期し、その結果をGithubのレポジトリにpushしておく。
本番環境とは切り離された検証環境のつもりでAmplifyで別アプリを作成する。
- Amplifyのウェブコンソールから「アプリケーションを構築」を押して、アプリ(名前はdestroyerとする)を作成する。
- Hosting environmentsからGithubを選択して、上記レポジトリのmainブランチと連携させる。
- 「ビルドの設定」画面で、Environmentを「新しい環境を作成」にし、Environment名は空欄のままにする。
- デプロイを開始し、デプロイされるのを待つ
Amplifyのウェブコンソール上でdestroyerを削除して、to_be_destroyedのBackend Environmentsが削除されるのを確認する
- Amplifyのウェブコンソールでdestroyerを開き、「アプリの削除」を押して削除する。
- destoryerが削除されたら、to_be_destroyedのBackend Environmentsが削除されているのを確認する。
mainが「Deletion completed」となっているのが確認できる。
原因
Amplifyにレポジトリ連携でデプロイする時、team-provider-info.jsonがレポジトリに入っていると、別Appであっても同一のCloudFormationスタックが用いられる。
そのため、Appを削除するとCloudFormationによって他Appと共用となってしまっているバックエンド環境が削除される。
対策(未検証)
- Amplifyと連携しているレポジトリからteam-provider-info.jsonを消す
- .gitignoreにteam-provider-info.jsonを追加する
- CloudFormationのスタック削除保護を有効化する
- バックアップを設定する
後記
代理店を通じてAWSにBackend Environmentsの復旧を依頼したが、Backend Environmentsに掛かるDynamoDB・S3は復旧できないとのこと。
amplify pullを実行すると、.gitignoreに色々追記されるが、team-provider-info.jsonは除外設定にならない。
本事象は私のプロジェクトの本格運用前に発生した。本格運用が始まった状態でこの問題が発生した場合にはより深刻な影響を及ぼしただろう。
DynamoDBのデータは、DataStoreがDynamoDBと同期していたブラウザのIndexedDBより救出された。
今年の2月に開始された弊プロジェクトでは、この他にも2度ほどAmplifyのバグを踏んでいる。
2023年11月14日日記
朝
特に記憶に無いです。
仕事
「Next.jsを使えば忌々しいAmplifyのDataStoreを無くせるんじゃね?」とか思って、社内システムの移植を開始した。もともとReactで動いていたので、3時間ほどでシステムがNext.jsの上で動くようになった。Next.jsの恩恵が受けられるのはこれからだ。
夜
「Next.jsを使えばBERTでSentence Embeddingを取るAPIをサーバーレスでつくれるんじゃね?」とかおもって実装した結果、比較的高性能な開発機であっても計算に3秒もかかることがわかり、検索には使えず無事死亡した。
デライトが落ちていた
「あれ」ってどんなんだったっけと思って、デライトで検索しようとしたところ、デライトが落ちていた(障害のお知らせ)。普段当たり前のようにデライトが使えているが、knownetの開発を通じてデライトが安定稼働していたことの異常さに気付きつつある。knownetの方はちゃんと動いている期間のほうが短い。
探そうとしていた情報については『t_wの輪郭』を参照して見つけられた。いざというときの保証として機能してくれた。
2023年11月11日日記
最近knownetの開発ばっかりやってる気がする
knownetのフロントエンドがAPIと通信する方式を、API.graphqlからDataStoreに切り替えた。すげー大変だったけど、自動でIndexedDBにデータを溜め込んでくれるので、APIが叩かれる回数が減り、動作がキビキビし、オフラインでも動くようになる。朝から7時間ほどコレに費やし、なんとか形になったので https://knownet.towasys.com へデプロイした。
この週末の間に、簡単でいいのでknownetに権限管理機能を付けたい。つまり、投稿をOwnerだけが編集できる設定を持たせたい。ついでに自分の投稿だけが見られる設定も作りたい。だいぶデライトの機能を取り込むことになる。
一風堂 is not for me
朝からプログラミングをがっつりやって結構疲れたのでラーメンを食べに家を出た。一風堂にきた。味玉とチャーシューを付けたら1800円になった。イライラするほど提供が遅かった。ラーメンにパーカーの紐が飛び込んだ。なんかもうダメな気がする。
スーパー
鶏もも肉と卵を買って帰った。鶏もも肉は、家の冷蔵庫にある白菜の残りと一緒に炊く。
包丁を鍋の底で研いだ
包丁が切れなくなってきており、前回鶏もも肉を切ったときに鶏皮を着るのに難渋したので、鍋の底でシャーシャーして研いだ。10回ほど軽くシャーシャーしただけだったが、かなり切れるようになった。砥石とかシャープナーとかいらんかったんや。
あれ
ノリと勢いで『t_wの輪郭』をReactで作り直しだウェーイってしてるけど、SEO死ぬんじゃねこれ
あとOGP対応無理くねコレ
何ならRSSも無理っぽい
AWS AmplifyでSSRする方法探すか
使用できますAWS Amplifyサーバー側レンダリング (SSR) を使用する Web アプリをデプロイしてホストします。現在、Amplify ホスティングは Next.js フレームワークを使用して作成されたアプリをサポートしています。
公式の日本語が怪しいけど、AWS AmplifyはNext.jsでSSR出来るらしい。
React+DataStoreからNext.jsに切り替えるぞッ!!!!
ここまで作ったフロントエンドを捨てることになるけど、メリットはあるし、やるしかねぇ。
- フロントエンドの実装はまだほとんど進んでない
- AmplifyでNext.jsで動かす勉強になる
DataStoreでConflictを回避するやつ
先にDataStore.queryを実行してデータを更新しておくと良い。
動作はAmplify StudioのData Managerで確認取ること。プログラムの作りによっては、ローカルでしか反映されていないことがある。
{test?.content!=undefined && <TextField backgroundColor="white" label={"test"} defaultValue={test?.content} onChange={async (event) => {
const test_db = await DataStore.query(Test, test.id);
if(test_db) {
console.log({ test_db , value:event.target.value});
const test_saved = await DataStore.save(Test.copyOf(test_db, (item: any) => {
item.content = event.target.value;
}));
console.log({test_saved});
set_test(test_saved);
}
}} />}