aws-sdk v3 を使うライブラリを作ったときは、なるべく peerDependencies に設定しよう
Tuesday, April 11, 2023 04:33:00 PM
先日 aws-sdk v2 が 2023 年中にメンテナンスモードになる という記事を書いて、実際自分たちで作っていた aws-sdk v2 でできていた CLI ツールも aws-sdk v3 に切り替えました。
CLIツールを v3 に移行したら、利用するアプリ側がコンパイルエラーになる
で、それを Lambda にデプロイするアプリの devDependencies に反映してみたところ、また型エラーが出るようになりました。
CLIツールでは @aws-sdk/client-lambda@3.310.0
に依存していて、 Lambda アプリ側は @aws-sdk/client-lambda@3.254.0
を使っていたためです。
error TS2345: Argument of type ‘typeof LambdaClient’ is not assignable to parameter of type ‘InstanceOrClassType
>’. Type ‘typeof LambdaClient’ is not assignable to type ‘ClassType >’.
で、それぞれの型定義への依存は "@aws-sdk/types": "*"
になっているので、lock ファイルの状態次第でそれぞれでバージョンが異なるものが入る場合があります。
そこで型が一致しない問題が発生してきます。
CLI ツールでは実行時に aws-sdk が必要になるので、 dependencies に設定していて、CLIツールを使う方のアプリは devDependencies に設定しているわけですが、それぞれの dependencies からインストールされる @aws-sdk/types
がドッチ?問題になってしまうという…
解決策
今回は自分たちで作ったライブラリだったので、CLIツール側の aws-sdk を devDependencies に変更して、CLIツールを使うアプリ側の aws-sdk 利用状況に依存するように変更しました。
"peerDependencies": {
"@aws-sdk/client-lambda": "^3.0.0"
},
これでアプリ側が @aws-sdk/client-lambda
を使っていればそのバージョンに依存するようになるし、使っていなければ 3系の最新が入るようになります。
ここで、この aws-sdk v3 シリーズを読んでいただいた懸命な皆様はお気づきだと思いますが Node.js v18 / aws-sdk v3 の Lambda アプリが突然動かなくなる でも書いた
peerDependencies
が指定されていたら、バージョンを揃えるために自分でインストールする
これが重要になってきます。 なので、自分で作ったライブラリで peerDependencies に指定したら、結局アプリ側で使ってなくてもバージョンを揃えるのに追加でインストールした方が良いということです。
aws-sdk v3 を安心して使うためには(追記)
- 基本的にバージョンは最新版、もしくは最新に近い同じバージョンに揃える
peerDependencies
が指定されていたら、バージョンを揃えるために自分でインストールする- 関数/クラス以外、たとえば enum の値などは基本的に利用しない
- 自作ライブラリで aws-sdk v3 に依存する場合は
peerDependencies
に指定する
大事なこと4つ目を追加しました。
aws-sdk@v3 のパッケージ管理に日々不安が募りますが、同様の問題に遭遇した人の解決に役立てれば幸いです。
aws-sdk v2 が 2023 年中にメンテナンスモードになる
Thursday, April 06, 2023 06:24:00 PM
aws-sdk v2 を使っている CLI ツールで aws 環境を操作していたら、見慣れないメッセージが出てきました。
(node:9129) NOTE: The AWS SDK for JavaScript (v2) will be put into maintenance mode in 2023.
AWS SDK v2 ってメンテナンスモードに入るんだ…
Twitter でも書いている人がいました
Anyone else seeing this new error from @awscloud sdk?
— David Wells (@DavidWells) February 16, 2023
This is showing to our CLI users and is… annoying to say the least. pic.twitter.com/KabEtFDKnl
これまでも複数回にわたって aws-sdk v3 の記事を書いてきましたが、これは Lambda にデプロイするアプリだから v3 に移行したのであって、CLIツールとかなら v3 に移行するモチベがあるかな….
ぶっちゃけ Lambda とかだとランタイムに追従すると sdk も上げないといけないので対応したけど、ツールなら対応しないですよね。
公式のリポジトリにも、サポートについて書かれています。
https://github.com/aws/aws-sdk-js#version-2x-support
そこにリンクされている メンテナンスポリシーページ にいくと、以下のような内容が記入されていました。
メンテナンス (フェーズ 3) -メンテナンス モードの間、AWS は SDK リリースを制限して、重大なバグ修正とセキュリティ問題のみに対処します。SDK は、新規または既存のサービスの API 更新を受け取ることも、新しいリージョンをサポートするために更新されることもありません。特に指定がない限り、メンテナンス モードのデフォルト期間は 12 か月です。
サポート終了 (フェーズ 4) - SDK がサポート終了に達すると、更新またはリリースを受け取ることができなくなります。以前に公開されたリリースは引き続きパブリック パッケージ マネージャーから入手でき、コードは GitHub に残ります。GitHub リポジトリはアーカイブされる場合があります。サポートが終了した SDK の使用は、ユーザーの判断で行われます。ユーザーが新しいメジャー バージョンにアップグレードすることをお勧めします。
v2 自体がリポジトリから無くなることはなさそうですが、膨大にありそうな v2 を使った CLI ツール群はどうするのかなぁ…
ちなみに Serverless Framerwork は PR Suppress AWS SDK v2 deprecation message でいったんメッセージ出力を OFF にしていますが、 v3 移行は大変だろうなぁ、という感想しかないです。
AWS SDK v3 は、これまでの記事でも書いてますが、結構パッケージ管理が残念な感じだったりするのと、書き方もめっちゃ変わっているので Serverless Framework 規模になると書き換えもかなり工数かかりそうだなぁと(いつかはやるんだろうけど)。
AWS さんが簡易にコンバートできるツールを作ってくれると良いんだろうけど、オプションの書き方も変わっているところがあったりするので、単純な変換も大変そうですね。
上記の引用ツイートのレスの中にもあるけど、v3 のドキュメントが不親切だというのは事実だし、良い解決策が 2023 年中に見つかると良いですね。 なんか感想ブログになっちゃいましたが、僕らのプロジェクトも v2 依存している CLI ツールは移行対象にしてなかったので、これから移行計画作らないとな、と思っています。
Node.js v18 / aws-sdk v3 の Lambda アプリが突然動かなくなる
Wednesday, April 05, 2023 05:08:00 PM
「Lambda アプリが突然動かなくなる」なんて、どうせバグなんでしょーというのが当然のリアクションですが、これは本当にバグなのか…
本当にあった怖い話をします。
ある日、Lambda アプリが突然動かなくなる
Node.js v18 のライタイムで動く Lambda にデプロイされているアプリで、ある日突然エラーが出るようになりました。
original: TypeError: Cannot read properties of undefined (reading ‘RUNNING’)
この部分ですが TypeScript のコードでは以下のようになっていました。
import {
DescribeExecutionCommand,
ExecutionDoesNotExist,
ExecutionStatus,
SFNClient,
StartExecutionCommand,
paginateListExecutions,
} from '@aws-sdk/client-sfn';
// 省略
if (latest?.status === ExecutionStatus.RUNNING) {
ExecutionStatus
は StepFunctions のクライアントで export されている値です。
StepFuntions のジョブが実行中かどうか判定している箇所で。少し前まで普通に動いていたのに….
Lambda アプリの構成
AWS Lambda は aws-sdk がランタイムにグローバルインストールされているので、最新版に追従して問題なければパッケージに含める必要はありません。 Lambda にデプロイするアプリケーションのサイズを少しでも減らすために、 aws-sdk は入れないようにしています。
node コンソールで確認してみる
手元では devDependencies に @aws-sdk/client-sfn
が入っているので、 node コンソールに入って require を実行してみました。
> const { ExecutionStatus} = require('@aws-sdk/client-sfn')
undefined
> ExecutionStatus
{
ABORTED: 'ABORTED',
FAILED: 'FAILED',
RUNNING: 'RUNNING',
SUCCEEDED: 'SUCCEEDED',
TIMED_OUT: 'TIMED_OUT'
}
ふむ、問題なさそうだが?
最新版の aws-sdk で変わったのだろうか? 一時的に最新版にバージョンアップをしてみて、確認してみます
> const { ExecutionStatus} = require('@aws-sdk/client-sfn')
undefined
> ExecutionStatus
undefined
えええええええーーー
aws-sdk の該当箇所の修正履歴をチェックする
hore(codegen): export enums as const
元のコード
/**
* @public
*/
export enum ExecutionStatus {
ABORTED = "ABORTED",
FAILED = "FAILED",
RUNNING = "RUNNING",
SUCCEEDED = "SUCCEEDED",
TIMED_OUT = "TIMED_OUT",
}
変更後のコード
/**
* @public
* @enum
*/
export const ExecutionStatus = {
ABORTED: "ABORTED",
FAILED: "FAILED",
RUNNING: "RUNNING",
SUCCEEDED: "SUCCEEDED",
TIMED_OUT: "TIMED_OUT",
} as const;
おいおい、これって @public
なのに後方互換性なくなっとるだろ….
なぜ undefined になるのか
enum はコンパイルされて JavaScript になると以下のようなコードになります。
var ExecutionStatus;
(function (ExecutionStatus) {
ExecutionStatus["ABORTED"] = "ABORTED";
ExecutionStatus["FAILED"] = "FAILED";
ExecutionStatus["RUNNING"] = "RUNNING";
ExecutionStatus["SUCCEEDED"] = "SUCCEEDED";
ExecutionStatus["TIMED_OUT"] = "TIMED_OUT";
})(ExecutionStatus = exports.ExecutionStatus || (exports.ExecutionStatus = {}));
でも export const as const
になると、JavaScript にはコンパイルされることなく、変数の利用箇所に埋め込みの形になります。
最初にも書きましたが、 aws-sdk v2 では普通だった
AWS Lambda は aws-sdk がランタイムにグローバルインストールされているので、最新版に追従して問題なければパッケージに含める必要はありません。 Lambda にデプロイするアプリケーションのサイズを少しでも減らすために、 aws-sdk は入れないようにしています。
こういう運用はすでにオワコンなんでしょうか? いやでも、v3 になってもランタイムに aws-sdk は入っています。
少なくとも ExecutionStatus
が内部変数で export されてない private な値だったら良いのですが、これはさすがにマズイんじゃないですかね?awsさん。
この問題が発生するケース
- AWS Lambda でランタイムの aws-sdk を使っていて、TypeScript から enum の値を参照していた場合(同一の変更ですべての enum が const に書き変わっています)
amplify とか Lambda でなくコンパイルされているケースでは問題は起きませんが、いやこういうのサクッと変更しちゃダメだと思うんですが… しかもランタイム側に入っているので、動作している Lambda アプリケーションが突然動作しなくなります。
aws-sdk v3 を安心して使うためには(追記)
- 基本的にバージョンは最新版、もしくは最新に近い同じバージョンに揃える
peerDependencies
が指定されていたら、バージョンを揃えるために自分でインストールする- 関数/クラス以外、たとえば enum の値などは基本的に利用しない
大事なこと3つ目を追加しました。
aws-sdk@v3 のパッケージ管理に日々不安が募りますが、同様の問題に遭遇した人の解決に役立てれば幸いです。
aws-sdk v3 でコンパイルエラーになる - その2
Tuesday, April 04, 2023 04:20:00 PM
先日の aws-sdk v3 で TS2345 が出てコンパイルエラーになる という記事でも書いたとおり、 @aws-sdk/client-xxxxx
を追加するときは
新しく
@aws-sdk/client-xxxx
を追加するときは、既存のクライアントも含めてすべて同じバージョンに変更する
のがオススメなのは変わりがないのですが、これだけだとうまく対応できないことがあったので、別記事として書いておきます。
ある日の変更前依存パッケージ
"devDependencies": {
"@aws-sdk/client-dynamodb": "^3.264.0",
"@aws-sdk/client-s3": "^3.264.0",
"@aws-sdk/client-s3-control": "^3.264.0",
"@aws-sdk/client-secrets-manager": "^3.264.0",
"@aws-sdk/lib-dynamodb": "^3.264.0",
}
DynamoDB, S3, Secret Manager を利用するようになっていました。
パッケージを追加したらエラーになる
で、そこに @aws-sdk/lib-storage
というパッケージを追加しようとしたところ、また先日と同様に TS2345
でコンパイルエラーになります。
ちゃんとバージョンをすべて最新にしてみたのですが、ダメでした。
ふたたび issue を探る
そうすると、issue ではなく discussions に変更されてしまったものを発見しました。
Peer dependencies not pinned for lib-dynamodb
なぜこんなことになるのか
やはりパッケージ管理が崩壊しているとしか思えないのですが、何でこうなっているのかというのを解説していきます。
以下は、今回追加しようとした @aws-sdk/lib-storage
の package.json
の一部です。
追加時点の lib-storage
のバージョンが 3.272.0
だったので、上記の変更前依存パッケージでインストール済みだったものも 3.272.0
に更新済みです。
"dependencies": {
"@aws-sdk/middleware-endpoint": "3.272.0",
"@aws-sdk/smithy-client": "3.272.0",
"buffer": "5.6.0",
"events": "3.3.0",
"stream-browserify": "3.0.0",
"tslib": "^2.3.1"
},
"peerDependencies": {
"@aws-sdk/abort-controller": "^3.0.0",
"@aws-sdk/client-s3": "^3.0.0"
},
peerDependencies
の依存がありますね。
で、すでにインストール済みだった @aws-sdk/client-dymanodb
の package.json
の一部も見てみましょう。
"dependencies": {
"@aws-crypto/sha256-browser": "3.0.0",
// 省略
"@aws-sdk/smithy-client": "3.272.0",
"@aws-sdk/types": "3.272.0",
// 省略
"uuid": "^8.3.2"
},
依存が多いのでちょっと省略しましたが、注目したいところだけ書きました。
こちらには peerDependencies
の依存はありません。
@aws-sdk/client-s3
は上記のとおりインストール済みだったので、 @aws-sdk/abort-controller
を見てみましょう。
"dependencies": {
"@aws-sdk/types": "3.289.0",
"tslib": "^2.3.1"
},
おや? @aws-sdk/types
のバージョンが違うじゃん…
“@aws-sdk/abort-controller”: “^3.0.0”,
なぜ、ここは ^3.0.0
なのだ??
というのが、最初のディスカッションでもふれられている訳ですが、本当にパッケージ管理が (ry
対応案
使っている aws-sdk のパッケージで peerDependencies
になっているのを調べて、すべてバージョン指定でインストールします。
ということで変更後の依存は以下のとおりにします。
"@aws-sdk/abort-controller": "3.272.0",
"@aws-sdk/client-dynamodb": "3.272.0",
"@aws-sdk/client-s3": "3.272.0",
"@aws-sdk/client-s3-control": "3.272.0",
"@aws-sdk/client-secrets-manager": "3.272.0",
"@aws-sdk/lib-dynamodb": "3.272.0",
"@aws-sdk/lib-storage": "3.272.0",
"@aws-sdk/smithy-client": "3.272.0",
"@aws-sdk/types": "3.272.0",
abort-controller, smithy-client, types が利用しているパッケージの中で peerDependencies
にあったので、すべてバージョンを揃えてコンパイルエラーは解消されました。
aws-sdk v3 を安心して使うためには
- 基本的にバージョンは最新版、もしくは最新に近い同じバージョンに揃える
peerDependencies
が指定されていたら、バージョンを揃えるために自分でインストールする
この2つとても大事です。
こんなの discussions に変更した上で放置していて良いのか?…
とても悲しい状況ですが、同様の問題に遭遇した人の解決に役立てれば幸いです。
aws-sdk v3 で TS2345 が出てコンパイルエラーになる
Monday, April 03, 2023 03:47:00 PM
dependabot で @aws-sdk/client のバージョンアップがコンパイルエラーになる
少し久しぶりの記事になってしまいましたが、この間も Node.js v18 / aws-sdk v3 への移行を行なっています。 一部のリポジトリではコードの移行は終わって、 dependabot でライブラリの最新追従を行なっているのですが、以下のようなコンパイルエラーが出るようになりました。
error TS2345: Argument of type 'typeof LambdaClient' is not assignable to parameter of type 'InstanceOrClassType<Client<ServiceInputTypes, MetadataBearer, any>>'.
Type 'typeof LambdaClient' is not assignable to type 'ClassType<Client<ServiceInputTypes, MetadataBearer, any>>'.
aws-sdk v3 では複数の aws サービスを使っていると複数のパッケージに依存するようになるのですが、複数のバージョンアップが dependabot によって PR されるうち、一部のアプデだけ上記のようなエラーになります。
issue を探してみる
aws-sdk の issue を調べていくと、それっぽいものがありました。
Typescript compilation problems since 3.52.0 in lib-dynamodb
この issue 自体はクローズされていないのですが、コメントのスレッドの中に有用な情報がありました。
@aws-sdk/types
が依存に入っていて、異なるバージョンの client-xxx があるとエラーになる(なんで package-lock.json を消してから npm i しなおすとうまくいくよ -> そんなんやるか!)@aws-sdk/client-xxxx
の各クライアントはすべて最新バージョンに追従してください
のようなものです(要約してあります)。
aws-sdk@v3 はサービスごとにパッケージを分割することで v2 と比べて良い、というのがウリなはずなんですが、これではパッケージ管理崩壊しているのでは?と思わなくもないですが、まぁ各クライアントのバージョンを合わせれば良いだけなので、従うことにしました。
ちなみにこの時点では複数の @aws-sdk/client-xxx
を全て最新版に追従することで解消されました。
この問題が発生する状況
この問題が発生する状況は以下のとおりです。
- すでに1つ以上の
@aws-sdk/client-xxxx
を入れていて、後日機能追加によって別のクライアントをインストールするとき - dependabot でパッケージごとにバージョンアップの PR が発動する
おすすめの対応
なので、現時点でのオススメの対応は以下のとおりです。
- 新しく
@aws-sdk/client-xxxx
を追加するときは、既存のクライアントも含めてすべて同じバージョンに変更する - dependabot による更新を
@aws-sdk/*
については無効にする
Github Actions の dependabot でアプデを無効にするには、 dependabot.yml を以下のように記述すれば良いです。
version: 2
updates:
- package-ecosystem: 'npm'
directory: '/'
ignore:
- dependency-name: '@aws-sdk/*'
# aws-sdk に対するすべての更新を無視
私たちは AWS Lambda の Node.js v18 ランタイムを使っているので、aws-sdk はランタイムにグローバルインストールされているから、あえて最新版に追従しなくても問題ないというのが主な理由です。 新しいクライアント追加のときに最新に追従すれば十分という判断です。
さいごに
aws-sdk@v3 を使ったアプリのナレッジが少ないので、何か小さなことでも記事にしていこうと思います。 同様の問題に遭遇した人の解決に役立てれば幸いです。
Recent Articles
- マルチプルレポをモノレポへコミットログを残しながら移行する 2023/09/27
- tsyringe を TypeScript 5 で使う方法 2023/05/02
- LocalStack を使って aws-sdk の Integration Test を実行する 2023/04/19
- AWS SDK v3 のモジュールと利用方法 2023/04/18
- ts-jest が esbuild/swc をトランスフォーマーに使って高速化していた 2023/04/13
- aws-sdk v3 を使うライブラリを作ったときは、なるべく peerDependencies に設定しよう 2023/04/11
- aws-sdk v2 が 2023 年中にメンテナンスモードになる 2023/04/06
- Node.js v18 / aws-sdk v3 の Lambda アプリが突然動かなくなる 2023/04/05
- aws-sdk v3 でコンパイルエラーになる - その2 2023/04/04
- aws-sdk v3 で TS2345 が出てコンパイルエラーになる 2023/04/03