https://docs.amplify.aws/gen1/javascript/build-a-backend/graphqlapi/data-modeling/
あれ
{
"formatter": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"complexity": {
"noStaticOnlyClass": "off"
}
}
},
"files": {
"ignore": [
"**/node_modules/**",
"**/amplify/**",
"**/ui-components/**",
"**/models/**",
"**/graphql/**",
]
}
}
あれ
最近「Amplifyの波動はこう言っている」とか言うようになってきた。Amplifyの裏で何が動いているかわからないので、「これまでの動きからいってなんかこうなりそうな気がする(けどアップデートされてるから今回どうなるかわからん)」という感じ。
あれ
なんかAmplifyのWebコンソールの見た目変わってるし、デプロイがなぜかこけよる。
今日中にデプロイしようぜって言ってたチケットあったけど、Amplifyのせいかデプロイできなかったので、同僚と「Amplifyが悪い」って言って、そのまま互いに帰宅した。
Amplify Hosting
あれ
「AmplifyのDataStoreやめるかぁ」
→ついでにNext.jsのServer Actionに統一するかぁ
→AmplifyのGraphQLのAPIをいい感じに叩けるようにするかぁ
→ついでにAmplifyJSをv5からv6にバージョン上げるかぁ(互換性なし)
→DataStoreのキャッシュ使わなくなったから画面遷移が遅くなったし、サーバー側で動かせるキャッシュ機構作るかぁ
とかやってたら、これまで作ったシステムの土台部分がほぼ書き換えになった。
あちこちのReact ComponentでDataStoreが使われているのを、いつかDataStoreを辞めようと思って少しずつまとめていたが、それでもかなりの量のコードを書き換えることになった。
Amplify上でSPAをホスティングする時のリダイレクト
Amplify Function
あれ
import-backend-storage
AmplifyでNext.jsのgetServerSideProsにユーザーアカウントを割り当ててAPIを叩く
idTokenをぶっこ抜く
InMemoryTokenStorage.ts
export class InMemoryTokenStorage implements Storage {
private storage: { [key: string]: string | null } = {}
get length(): number {
return Object.keys(this.storage).length
}
key(index: number): string | null {
return Object.keys(this.storage)[index]
}
getItem(key: string): string | null {
return this.storage[key]
}
setItem(key: string, value: string): void {
this.storage[key] = value
}
removeItem(key: string): void {
delete this.storage[key]
}
clear(): void {
this.storage = {}
}
}
設定
const token_storage = new InMemoryTokenStorage();
Amplify.configure({
...awsmobile,
Auth: {
storage: token_storage,
}
})
ぶっこ抜いたidTokenを使ってAPIを叩く
async function idToken_get() {
(await public_user_account_get());
return Object.entries(token_storage.storage).map(([key, value]) => `${key}=${value}`).join("; ");
}
async function public_user_account_get() {
return await (async () => {
try {
return await Auth.currentAuthenticatedUser();
} catch (error) {
try {
return await Auth.signIn(process.env.PUBLIC_EMAIL_ADDRESS ?? "", process.env.PUBLIC_PASSWORD ?? "");
} catch (error) {
return undefined;
}
}
})()
}
const SSR = withSSRContext({ req: { headers: { cookie: await idToken_get() } } });
const result = await SSR.API.graphql({
query: deleteRelation,
variables: {
input: {
id: relation.id,
_version: relation._version,
}
}
})
参考
InMemoryTokenStorageのパクリ元:『Amplifyでアクセストークンをin-memoryに置いてみる』
amplify override
『Amplify override でバックエンドリソースをCDKでカスタマイズ』
あれ
Amplifyに乗っけたNext.jsから直接DynamoDBたたくの大変っぽい。テーブル名を同定でけへん。
あれ
CustomerError: The size of the build output (389192469) exceeds the max allowed size of230686720 bytes. Please reduce the size ofyour build output and try again.
あっ
ちくしょう
Amplify死ね
AWS君さぁ……Lambdaのサイズ制限にしろ、Amplifyのサイズ制限にしろ、厳しすぎやしませんかね……
AmplifyのBuildでムリクソgit lfsを使う方法
Amazon Linux 2023で以下のymlを設定する
version: 1
backend:
phases:
preBuild:
commands:
build:
commands:
- '# Execute Amplify CLI with the helper script'
- amplifyPush --simple
frontend:
phases:
preBuild:
commands:
- npm ci
- sudo yum install git-lfs -y
- git lfs install
- git pull
build:
commands:
- npm run build
artifacts:
baseDirectory: .next
files:
- '**/*'
cache:
paths:
- node_modules/**/*
あれ
『Amplify爆死レポート』をFediverseに流したところ、「わっかるー」と帰ってきた人とFFになった。
その人のタイムラインを遡っていたら、Azureの愚痴が度々書かれており、「AWSからAzure行くぞッ!」と思っていた矢先だったため、「Azureもあかんか……」となっている。逃げ道が無いではないか。
Amplify Gen2
『[amplify] 本番データが全削除された話』
あれ
AWSのマンガを読むと、いかにも本番運用に強いと捉えてしまいそうになる……
データを持たないステートレスなサイトを運営するのであれば、Amplifyは便利かと思います。サーバーレスですので、オートスケールして大量アクセスに耐えられますし(ただし財布は死ぬ)、万が一が有ったとしてもデプロイし直せば簡単に復旧が可能です。
ただ、社内の重要書類を管理するような、データに重点をおいたアプリケーションの開発となると、今回の事象もあってまだ信頼に足るものにはなってないと思います。
また、利用者の権限管理(Access Control)をAmplifyでやりたいとかいう話になってくると、Lambda Authorizerというのを使って自前でRBACなどを実装する羽目になるので、これまた苦労します。英語の論文を一本読む必要が出てきます。
あれ
初期設定がデータを吹っ飛ばすようになっている仕組みなのは困りますね。
このあたりが「AmplifyはPoCに最適」と言われ、本番環境での運用事例が乏しい所以かと思います。
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のバグを踏んでいる。
Next.jsをAWS Amplifyで動かす
フロントエンドのビルドの設定をいじる(baseDirectory: .next
にする)。
frontend:
phases:
preBuild:
commands:
- npm ci
build:
commands:
- npm run build
artifacts:
baseDirectory: .next
files:
- '**/*'
cache:
paths:
- node_modules/**/*
WEB_COMPUTEに切り替える。
aws amplify update-app --app-id {app_id} --platform WEB_COMPUTE
フレームワークを誤認識する場合はNext.jsと明示する。
aws amplify update-branch --app-id <value> --branch-name <value> --framework 'Next.js - SSR'
https://github.com/aws-amplify/amplify-hosting/issues/3168
上記設定の後に再構築する。
コマンドをやるときは、CloudShellが便利。
Amplifyでビルドあとのデプロイでエラーが出る
2023-11-14T23:35:19 [INFO]: Beginning deployment for application XXXXXXX, branch:main, buildId 0000000082
2023-11-14T23:35:20 [INFO]: Got archive: 672783 bytes
2023-11-14T23:35:20 [ERROR]: {"message":"Unsupported Node.js version: v20.9.0. Try re-building the App with a supported Node.js version.","code":"UnsupportedRuntime"}
AmplifyでNode.js 20を使う方法で20に設定していたのを18にしたらなんか動いた。
AmplifyでNode.js 20を使う方法
AmplifyでNext.js 14をビルドする方法
Amplifyの構築イメージでAmazon Linux 2023が使えるようになっていた
こんなん前からあったっけ
2023年11月14日日記
朝
特に記憶に無いです。
仕事
「Next.jsを使えば忌々しいAmplifyのDataStoreを無くせるんじゃね?」とか思って、社内システムの移植を開始した。もともとReactで動いていたので、3時間ほどでシステムがNext.jsの上で動くようになった。Next.jsの恩恵が受けられるのはこれからだ。
夜
「Next.jsを使えばBERTでSentence Embeddingを取るAPIをサーバーレスでつくれるんじゃね?」とかおもって実装した結果、比較的高性能な開発機であっても計算に3秒もかかることがわかり、検索には使えず無事死亡した。
デライトが落ちていた
「あれ」ってどんなんだったっけと思って、デライトで検索しようとしたところ、デライトが落ちていた(障害のお知らせ)。普段当たり前のようにデライトが使えているが、knownetの開発を通じてデライトが安定稼働していたことの異常さに気付きつつある。knownetの方はちゃんと動いている期間のほうが短い。
探そうとしていた情報については『t_wの輪郭』を参照して見つけられた。いざというときの保証として機能してくれた。
あれ
なんでAmplifyでConflict Resolutionを変えたときに、自動でデータ変換をやってくれへんねん。
自前でSQL書くのめんどくさすぎる。しかもSQLで一回で一括変換できないから、各レコードのID取得→IDでレコード更新 をレコード分だけやる羽目になる。時間かかりよる。
レコード更新にxargsを使っているので、-Pで並列化して高速化を試みたが、速くなってないっぽい。
あれ
AmplifyのGraphQL APIで"ベクトル"を含む文字が検索できないっぽい
ちがうな、コレはデータかインデックスが壊れてるっぽいな
AWS AmplifyでGo言語とNext.jsから成るアプリをビルドするアレ
version: 1
backend:
phases:
preBuild:
commands:
- wget --no-verbose https://go.dev/dl/go1.21.0.linux-amd64.tar.gz
- rm -rf /usr/local/go
- tar -C /usr/local -xzf go1.21.0.linux-amd64.tar.gz
build:
commands:
- '# Execute Amplify CLI with the helper script'
- export PATH=$PATH:/usr/local/go/bin
- go version
- amplifyPush --simple
frontend:
phases:
preBuild:
commands:
- npm ci
build:
commands:
- npm run build
artifacts:
baseDirectory: .next
files:
- '**/*'
cache:
paths:
- node_modules/**/*
あれ
AmplifyでNext.jsが動いたああああああ
https://main.du4rqori3cgjf.amplifyapp.com/
こっからどうしたら良かったんだっけ……
Next.js触ったのだいぶ前なので忘れてしまった。
あれ
ノリと勢いで『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で動かす勉強になる
Go言語のAmplify functionでGraphQL APIを叩くコード(IAM)
var ENDPOINT = os.Getenv("API_AMPLIFY_GRAPHQLAPIENDPOINTOUTPUT")
func query(query_string string) string {
json_string := `{"query":"` + strings.Replace(query_string, "\n", "\\n", 100) + `"}`
req, err := http.NewRequest(
"POST",
ENDPOINT,
bytes.NewBuffer([]byte(json_string)),
)
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")
//Authの設定によっては署名が必要
config := aws.Config{Region: aws.String("ap-northeast-1")}
sess := session.Must(session.NewSession(&config))
signer := v4.NewSigner(sess.Config.Credentials)
signer.Sign(req, bytes.NewReader([]byte(json_string)), "appsync", "ap-northeast-1", time.Now())
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
panic(err)
}
return string(body)
}
Go言語のAmplify functionでGraphQL APIを叩くコード(API Key)
var ENDPOINT = os.Getenv("API_AMPLIFY_GRAPHQLAPIENDPOINTOUTPUT")
var APIKEY = os.Getenv("API_AMPLIFY_GRAPHQLAPIKEYOUTPUT")
func query(query_string string) string {
json_string := `{"query":"` + strings.Replace(query_string, "\n", "\\n", 100) + `"}`
req, err := http.NewRequest(
"POST",
ENDPOINT,
bytes.NewBuffer([]byte(json_string)),
)
if err != nil {
panic(err)
}
req.Header.Set("X-Api-Key", APIKEY)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
panic(err)
}
return string(body)
}
『AWS AmplifyでReact(TypeScript)、GraphQL、Lambda(Go)なアプリを作ってみた』
あれ
export CGO_ENABLED=0 && amplify push functionで解決(しなさい)
あれ
ログ出力
以下のセクションでは、コード内のロギング呼び出しを示しています。ここをクリックし、 で対応する CloudWatch ロググループを表示できます。/var/task/main: /lib64/libc.so.6: version `GLIBC_2.34' not found (required by /var/task/main)
/var/task/main: /lib64/libc.so.6: version `GLIBC_2.32' not found (required by /var/task/main)
2023/09/23 11:04:56 exit status 1
/var/task/main: /lib64/libc.so.6: version `GLIBC_2.34' not found (required by /var/task/main)
/var/task/main: /lib64/libc.so.6: version `GLIBC_2.32' not found (required by /var/task/main)
2023/09/23 11:04:56 exit status 1
START RequestId: b793e5d1-19ba-451d-8c01-2b4f20a78787 Version: $LATEST
RequestId: b793e5d1-19ba-451d-8c01-2b4f20a78787 Error: Runtime exited with error: exit status 1
Runtime.ExitError
END RequestId: b793e5d1-19ba-451d-8c01-2b4f20a78787
REPORT RequestId: b793e5d1-19ba-451d-8c01-2b4f20a78787 Duration: 204.05 ms Billed Duration: 205 ms Memory Size: 128 MB Max Memory Used: 5 MB
はぁ〜〜〜〜ウンカス
あれ
AmplifyがGo言語と相性悪くてキレてる
あれ
あれ
リリース作業ですげー疲れた。実労1時間だが、これだけでヘボヘボのヘボン式となった。ヘボン式がへぼいと言いたいわけではない。疲れていると余計なものが出てくる。
「Amplifyと繋がってるGitホスティングサービスの変更(Amplifyのバグのせいですげーテクいし本番環境を一回吹っ飛ばして立て直す)」と「DBのテーブルの多対多への変更に伴うデータ変換」が重なってめちゃ気を使う作業群となってしまった。今思うとそんなもん重ねるなとなる。
でも、これ以降は他のメンバーが開発に参加できるので、開発が加速するはずだ。社内標準のGitホスティングサービスに移行できたし、データ構造が固まったのでフロントエンドの開発を並列化して進められる。
あれ
AWS Amplifyでamplify pushするとエラーが起きる。
{The following resource(s) failed to create: [LambdaFunction]. K#/2019}
というエラーが出ている
CloudWatchには{Resource handler returned message: "Unzipped size must be smaller than 262144000 bytes (Service: Lambda, Status Code: 400, Request ID: xyz)" (RequestToken: abcd, HandlerErrorCode: InvalidRequest) K#/9DA6}
というエラーが出ている。
pushしているLambda関数が大きすぎるらしい。
262144000 bytes ということは、260MBまでとのこと
あれ
tensorflow/tfjsを Lambda Layerにしてみる
ダメだったらUniversal Sentence Encoder lite以外でnodejsにてsentence embeddingできる何かを探す
EnergeticAI Embeddingsとか良さそうなんだけど、modelが”en”しかないのが気にかかる。日本語でもいけるんだろうか?
embeddingはpythonでやるのが王道なんだろうけど、AWS AmplifyのfunctionとしてPythonを動かすのは私には難しすぎて無理だった。やはりPythonが嫌いだ。
あれ
良いホスティングサービス知りたい
Reactで書いたウェブアプリをAWS Amplifyでホスティングしてる
同僚にはVercelにしろって言われてる
AWS Amplify の@searchableが Amazon OpenSearch Serverless に対応して欲しい
きっとそのうち対応するだろう。
『AWS Amplify を使って簡単に Algolia と連携した検索機能を作る』
AmplifyのStorage.getがキャッシュする
cacheControl: 'no-cache'
をつければキャッシュしなくできる。
Storage.get(post_to_display.id, {
level: 'public',
cacheControl: 'no-cache',
download: true,
}).then(async (result: any) => {
const text = await result.Body?.text();
set_body_html(text);
});
https://github.com/aws-amplify/amplify-js/issues/6413#issuecomment-720499530
DataStore
『API (GraphQL) Make your data searchable』
AWS AmplifyでGraphQL Schemaに@searchableを設定するとデプロイに時間がかかる
インデックス作るのも時間かかってそう。
@searchableを設定すると、裏でOpenSearch(Elasticsearch)がデプロイされているそうな
@searchable
AWS AmplifyのGraphQL APIでAPI keyを使う
import awsExports from './aws-exports';
const graphql_result = await API.graphql({
query: listPostByUpdatedAtWhereStatus,
variables: {
status: Post_Status.LIVE,
sortDirection: ModelSortDirection.DESC,
limit: 20
},
authMode: "API_KEY",
authToken: awsExports.aws_appsync_apiKey
}) as GraphQLResult<ListPostByUpdatedAtWhereStatusQuery>
listPostByUpdatedAtWhereStatus
とListPostByUpdatedAtWhereStatusQuery
は良きように変える。
GraphQL API
Amplify Boost Up #02
AWS Amplify Studio
AWS AmplifyとAWS Copilotはすぐにアプリを公開できるためPoCやモックを作るのに向いている
ほんとAWS AmplifyとAWS Copilotはまじでインフラエンジニアがいらないし秒でアプリ公開できるからPoCやモック作るのにおすすめ