t_wの輪郭

Feedlyでフォローするボタン
AWS『個人開発のコストはDB次第』Amplify
『t_wの輪郭』をAWS Amplifyに移行『個人開発のコストはDB次第』あれ2023年11月14日日記DataStoreあれ『Is there a way to specifiy thedynamodb tablename when creating a api resource using amplify?』Amplify Gen2AmplifyのBuildでムリクソgit lfsを使う方法『AWS AmplifyでReact(TypeScript)、GraphQL、Lambda(Go)なアプリを作ってみた』GraphQL APIAmplify GraphQL TransformerGo言語のAmplify functionでGraphQL APIを叩くコード(IAM)あれ『API (GraphQL) Make your data searchable』AWS AmplifyのGraphQL APIでAPI keyを使うあれあれAmplify上でSPAをホスティングする時のリダイレクトAmplify Functionあれimport-backend-storageAmplifyでNext.jsのgetServerSideProsにユーザーアカウントを割り当ててAPIを叩くamplify override『Amplify override でバックエンドリソースをCDKでカスタマイズ』あれamplifyAmplify UIあれAWS Amplify StudioAWS Amplifyで検証用アプリを作ったあとに削除したら、大本のアプリのBackend environmentsが意図せず消されたあれあれAWS AmplifyとAWS Copilotはすぐにアプリを公開できるためPoCやモックを作るのに向いているAmplify Boost Up #02あれあれAmplifyでNode.js 20を使う方法AmplifyでNext.js 14をビルドする方法Amplifyでビルドあとのデプロイでエラーが出るAmplifyの構築イメージでAmazon Linux 2023が使えるようになっていたAmplifyへNext.js 14をデプロイするときに『unhandledRejection ReferenceError: Headers is not defined』と出るときの対策あれ@searchableあれあれAmplify HostingAWS AmplifyでGo言語とNext.jsから成るアプリをビルドするアレGo言語のAmplify functionでGraphQL APIを叩くコード(API Key)あれあれあれあれあれAmplifyのStorage.getがキャッシュするあれAmplifyが悪いあれNext.jsとAmplifyでcognitoの認証を実装『Amplify SDK(JavaScript)でCognitoの認証機能を試す』Next.jsをAWS Amplifyで動かすAWS Amplify の@searchableが Amazon OpenSearch Serverless に対応して欲しいAWS AmplifyでGraphQL Schemaに@searchableを設定するとデプロイに時間がかかる『AWS Amplify フレームワークの使い方Part18〜GraphQL Transform v2 @hasOne/@hasMany/@belongsTo/@manyToMany (旧@ connection)編〜』『AWS Amplify を使って簡単に Algolia と連携した検索機能を作る』Storage『Export Amplify project to CDK - JavaScript - AWS Amplify Gen 1 Documentation』『[amplify] 本番データが全削除された話』あれ『Customize your data model - JavaScript - AWS Amplify Gen 1 Documentation』

あれ

2024/10/8 9:49:00
{
	"formatter": {
		"enabled": true
	},
	"linter": {
		"enabled": true,
		"rules": {
			"complexity": {
				"noStaticOnlyClass": "off"
			}
		}
	},
	"files": {
		"ignore": [
			"**/node_modules/**",
			"**/amplify/**",
			"**/ui-components/**",
			"**/models/**",
			"**/graphql/**",
		]
	}
}

あれ

2024/5/17 22:09:00

最近「Amplifyの波動はこう言っている」とか言うようになってきた。Amplifyの裏で何が動いているかわからないので、「これまでの動きからいってなんかこうなりそうな気がする(けどアップデートされてるから今回どうなるかわからん)」という感じ。

あれ

2024/5/13 19:12:00

なんかAmplifyのWebコンソールの見た目変わってるし、デプロイがなぜかこけよる。

今日中にデプロイしようぜって言ってたチケットあったけど、Amplifyのせいかデプロイできなかったので、同僚と「Amplifyが悪い」って言って、そのまま互いに帰宅した。

あれ

2024/3/22 18:43:00

「AmplifyのDataStoreやめるかぁ」
→ついでにNext.jsのServer Actionに統一するかぁ
→AmplifyのGraphQLのAPIをいい感じに叩けるようにするかぁ
→ついでにAmplifyJSをv5からv6にバージョン上げるかぁ(互換性なし)
→DataStoreのキャッシュ使わなくなったから画面遷移が遅くなったし、サーバー側で動かせるキャッシュ機構作るかぁ

とかやってたら、これまで作ったシステムの土台部分がほぼ書き換えになった。

あちこちのReact ComponentでDataStoreが使われているのを、いつかDataStoreを辞めようと思って少しずつまとめていたが、それでもかなりの量のコードを書き換えることになった。

あれ

2023/12/5 7:58:00

AWS CLIのimport-backend-storageを使えば、Amplifyのアプリをバックアップから復旧させるのが楽そう。

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に置いてみる』

あれ

2023/12/3 12:52:00

Amplifyに乗っけたNext.jsから直接DynamoDBたたくの大変っぽい。テーブル名を同定でけへん。

あれ

2023/12/2 17:34:00

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のサイズ制限にしろ、厳しすぎやしませんかね……

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/**/*

あれ

2023/11/23 9:04:00

Amplify爆死レポート』をFediverseに流したところ、「わっかるー」と帰ってきた人とFFになった。

その人のタイムラインを遡っていたら、Azureの愚痴が度々書かれており、「AWSからAzure行くぞッ!」と思っていた矢先だったため、「Azureもあかんか……」となっている。逃げ道が無いではないか。

あれ

2023/11/21 22:49:00

AWSのマンガを読むと、いかにも本番運用に強いと捉えてしまいそうになる……

データを持たないステートレスなサイトを運営するのであれば、Amplifyは便利かと思います。サーバーレスですので、オートスケールして大量アクセスに耐えられますし(ただし財布は死ぬ)、万が一が有ったとしてもデプロイし直せば簡単に復旧が可能です。

ただ、社内の重要書類を管理するような、データに重点をおいたアプリケーションの開発となると、今回の事象もあってまだ信頼に足るものにはなってないと思います。
また、利用者の権限管理(Access Control)をAmplifyでやりたいとかいう話になってくると、Lambda Authorizerというのを使って自前でRBACなどを実装する羽目になるので、これまた苦労します。英語の論文を一本読む必要が出てきます。

あれ

2023/11/21 21:42:00

初期設定がデータを吹っ飛ばすようになっている仕組みなのは困りますね。

このあたりが「AmplifyはPoCに最適」と言われ、本番環境での運用事例が乏しい所以かと思います。

再現手順

Amplifyを触ったことがある人を対象としているため、画像を貼ったりせず、事細かには説明しない。適宜補完してほしい。

本番と見なすAmplifyのアプリを作成する

ダミーのウェブアプリを作る
  1. Githubに空のレポジトリを作成する
  2. GithubからレポジトリをCloneする
  3. ローカルの端末でnpx create-react-app amplify_the_destroyerなどと実行して、テスト用に適当なウェブアプリを作成する。ここでnext.jsで作るとややこしいことになるのでやってはいけない。
Amplifyのウェブコンソールでの作業
  1. Amplifyのウェブコンソールから「アプリケーションを構築」を押して、アプリ(名前はto_be_destroyedとする)を作成する。
ローカルの端末での作業
  1. Backend environmentsにstagingがあるので、これをamplify pull --appId {appId} --envName stagingで取得する。
  2. git add .git commit -m "init"git pushを実行して、レポジトリにコードを反映させる。
Amplifyのウェブコンソールでの作業
  1. Hosting environmentsからGithubを選択して、上記レポジトリのmainブランチと連携させる。
  2. 「ビルドの設定」画面で、Environmentを「新しい環境を作成」にし、Environment名は空欄のままにする。
  3. デプロイを開始し、デプロイされるのを待つ。
作業結果

下の画像のようになれば成功だ。Amplifyを使っている人には見慣れた光景かと思う。

この後、ローカルの端末でamplify pull --appId {appId} --envName mainを実行してmainと同期し、その結果をGithubのレポジトリにpushしておく。


本番環境とは切り離された検証環境のつもりでAmplifyで別アプリを作成する。

  1. Amplifyのウェブコンソールから「アプリケーションを構築」を押して、アプリ(名前はdestroyerとする)を作成する。
  2. Hosting environmentsからGithubを選択して、上記レポジトリのmainブランチと連携させる。
  3. 「ビルドの設定」画面で、Environmentを「新しい環境を作成」にし、Environment名は空欄のままにする。
  4. デプロイを開始し、デプロイされるのを待つ

Amplifyのウェブコンソール上でdestroyerを削除して、to_be_destroyedのBackend Environmentsが削除されるのを確認する

  1. Amplifyのウェブコンソールでdestroyerを開き、「アプリの削除」を押して削除する。
  2. 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のバグを踏んでいる。

フロントエンドのビルドの設定をいじる(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が便利。

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にしたらなんか動いた。

2023年11月14日日記

2023/11/15 0:26:00

 特に記憶に無いです。

仕事

 「Next.jsを使えば忌々しいAmplifyDataStoreを無くせるんじゃね?」とか思って、社内システムの移植を開始した。もともとReactで動いていたので、3時間ほどでシステムがNext.jsの上で動くようになった。Next.jsの恩恵が受けられるのはこれからだ。

 「Next.jsを使えばBERTSentence Embeddingを取るAPIをサーバーレスでつくれるんじゃね?」とかおもって実装した結果、比較的高性能な開発機であっても計算に3秒もかかることがわかり、検索には使えず無事死亡した。

デライトが落ちていた

 「あれ」ってどんなんだったっけと思って、デライトで検索しようとしたところ、デライトが落ちていた(障害のお知らせ)。普段当たり前のようにデライトが使えているが、knownetの開発を通じてデライトが安定稼働していたことの異常さに気付きつつある。knownetの方はちゃんと動いている期間のほうが短い。

 探そうとしていた情報については『t_wの輪郭』を参照して見つけられた。いざというときの保証として機能してくれた。

あれ

2023/11/11 9:31:00

なんでAmplifyでConflict Resolutionを変えたときに、自動でデータ変換をやってくれへんねん。

自前でSQL書くのめんどくさすぎる。しかもSQLで一回で一括変換できないから、各レコードのID取得→IDでレコード更新 をレコード分だけやる羽目になる。時間かかりよる。

レコード更新にxargsを使っているので、-Pで並列化して高速化を試みたが、速くなってないっぽい。

あれ

2023/9/30 14:10:00

AmplifyのGraphQL APIで"ベクトル"を含む文字が検索できないっぽい

ちがうな、コレはデータかインデックスが壊れてるっぽいな

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/**/*

あれ

2023/9/24 16:30:00

ノリと勢いで『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で動かす勉強になる
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)
}
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)
}

あれ

2023/9/23 20:17:00

export CGO_ENABLED=0 && amplify push functionで解決(しなさい)

あれ

2023/9/23 20:07:00

ログ出力
以下のセクションでは、コード内のロギング呼び出しを示しています。ここをクリックし、 で対応する 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

はぁ〜〜〜〜ウンカス

あれ

2023/9/11 18:42:00

リリース作業ですげー疲れた。実労1時間だが、これだけでヘボヘボのヘボン式となった。ヘボン式がへぼいと言いたいわけではない。疲れていると余計なものが出てくる。

「Amplifyと繋がってるGitホスティングサービスの変更(Amplifyのバグのせいですげーテクいし本番環境を一回吹っ飛ばして立て直す)」と「DBのテーブルの多対多への変更に伴うデータ変換」が重なってめちゃ気を使う作業群となってしまった。今思うとそんなもん重ねるなとなる。

でも、これ以降は他のメンバーが開発に参加できるので、開発が加速するはずだ。社内標準のGitホスティングサービスに移行できたし、データ構造が固まったのでフロントエンドの開発を並列化して進められる。


あれ

2023/6/11 23:41:00

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までとのこと

あれ

2023/6/10 14:50:00

tensorflow/tfjsを Lambda Layerにしてみる
ダメだったらUniversal Sentence Encoder lite以外でnodejsにてsentence embeddingできる何かを探す

EnergeticAI Embeddingsとか良さそうなんだけど、modelが”en”しかないのが気にかかる。日本語でもいけるんだろうか?

embeddingはpythonでやるのが王道なんだろうけど、AWS AmplifyのfunctionとしてPythonを動かすのは私には難しすぎて無理だった。やはりPythonが嫌いだ。

あれ

2023/6/6 21:42:00

AWS Amplifyでいい感じの権限管理の仕組み作ろうとして沼にハマりましたマン

今日何とか山場を越えた

あれ

2023/6/6 21:42:00

良いホスティングサービス知りたい

Reactで書いたウェブアプリをAWS Amplifyでホスティングしてる

同僚にはVercelにしろって言われてる

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>

listPostByUpdatedAtWhereStatusListPostByUpdatedAtWhereStatusQueryは良きように変える。