DynamoDBのテーブル定義を取得して別リージョンにコピーを作成する

DynamoDBのテーブル定義を取得して別リージョンにコピーを作成する

AWS DynamoDBでシステムを組むとテーブルは当然1つ2つでは済まず、システムとしてたくさんのテーブルを作ることになります。システムをテスト用や本番環境などで別リージョンにコピーを作らないといけないこともあり、ボタンひとつで簡単にコピーできればいいのですがそういったツールもなく手作業になっています。AWSCLIコマンドを組み合わせればある程度テーブル定義の取得から別リージョンに新たにテーブル作成することができます。

テーブル一覧を取得

aws dynamodb list-tables

テーブル定義を取得

aws dynamodb describe-table --table-name テーブル名 > 出力ファイル名.json

テーブルリストが取得できるので上記のdescribe-tableで定義を取得しJSONファイルを保存します。このdescribe-table情報はテーブル作成で要らない情報も入っていますのでそれを編集します。下記のElementを削除します。

['TableStatus', 'TableSizeBytes','TableId','TableArn', 'ItemCount','CreationDateTime', 'NumberOfDecreasesToday','IndexStatus','IndexSizeBytes','IndexArn']

テーブル作成

describe-tableのJSONが綺麗に修正できたらcreate-tableを実行します。

aws dynamodb create-table --table-name テーブル名 --cli-input-json file://テーブル定義.json

この手順で別リージョンにコピーできるのですがdescribe-tableの編集が面倒です。なのでわたしの場合Node.jsで組んで簡単に引越しできるようにしました。

https://github.com/mojeld/copyDynamoDBTabledefinitionToAnotherRegion

node index.js ap-northeast-1 us-west-2

上記のようにソースリージョンとコピー先リージョンを指定するとコピーできます。

Lambda Node.js MySQL接続でのUnknown application error occurred

PROTOCOL_SEQUENCE_TIMEOUT

AWS LambdaNode.js 12で関数を作成し、npm install mysqlを使ってMySQLデータベースに接続した場合、何度か実行していたらたまに「Internal Server Error」出ていましてLOGを見ると「Unknown application error occurred」と書いていました。

LOGを追っていくと下記のような「Quit inactivity timeout」を発見した。

2020-12-31T09:53:06.051Z	8d702d7b-XXXX-XXXX-99a1-XXXXX231d3ad	ERROR	Uncaught Exception 	{
    "errorType": "Error",
    "errorMessage": "Quit inactivity timeout",
    "code": "PROTOCOL_SEQUENCE_TIMEOUT",
    "fatal": true,
    "timeout": 30000,
    "stack": [
        "Error: Quit inactivity timeout",
        "    at Quit.<anonymous> (/var/task/node_modules/mysql/lib/protocol/Protocol.js:160:17)",
        "    at Quit.emit (events.js:314:20)",
        "    at Quit._onTimeout (/var/task/node_modules/mysql/lib/protocol/sequences/Sequence.js:124:8)",
        "    at Timer._onTimeout (/var/task/node_modules/mysql/lib/protocol/Timer.js:32:23)",
        "    at listOnTimeout (internal/timers.js:554:17)",
        "    at processTimers (internal/timers.js:497:7)"
    ]
}

原因は、MySQLとのコネクションを切るためのend()でした。

end(callback?: (err?: MysqlError) => void): void;
end(options: any, callback: (err?: MysqlError) => void): void;

上記のようになってるので、Promiseでラップした方がいいようでした。

const mysqlEnd  = () => {
	return new Promise((resolve, reject) => {
		try {
			mysqlのインスタンス.end({timeout: 3000}, (err) => {
				if (err) {
					console.log(err)
					reject(null)
				} else {
					resolve(null)
				}
			})
		} catch (_e1) {
			console.log(_e1)
		}
	})   
}

これで、いまのところ「Internal Server Error」は出ていません。たまにしか症状が出ないので確認が出来ていません。

Amazon API Gateway CORS の有効化

API Gateway CORS有効

Amazon API Gateway がブラウザコンソール画面から[リソース|アクション]「CORS の有効化」画面内[CORS を有効にして既存の CORS ヘッダーを置換]ボタンをクリックすることでCORS有効化されます。然しメソッドの実行設定でLambdaを指定しLambda プロキシ統合の使用」チェックしてしまうと「CORS の有効化」が機能しなくなるようです。これはLambda側にヘッダーの制御が渡ったということだと、私は解釈しています。従って、Lambda側でコード内にHTTPヘッダーを書きCORSを有効にする記述をすればCORSとして利用できます。

「Lambda プロキシ統合の使用」をOFFにした場合HTTPヘッダーを確認すると「access-control-allow-origin: *」がついていました。
「Lambda プロキシ統合の使用」をOFFにした場合HTTPヘッダーを確認すると「access-control-allow-origin: *」がついていました。

Lambda プロキシ統合の使用」をONにした場合、access-control-allow-originが消えてしまいブラウザからAjaxなどでAPIのデータが取得できなくなります。API Gatewayの「Lambda プロキシ統合の使用」をONにした場合はLambda側で下記のように記述します。

exports.handler = async (event) => {
    // TODO implement
    const response = {
        headers: {
            "Access-Control-Allow-Origin" : "*", 
            "Access-Control-Allow-Credentials" : true
        }, 
        statusCode: 200,
        body: JSON.stringify('Hello from Lambda!'),
    };
    return response;
};

headersというエレメントを追加し“Access-Control-Allow-Origin”“Access-Control-Allow-Credentials”を追加します。ヘッダーを確認すると下記のように2行が追加されていました。

Lambda側でCORS HTTPヘッダーを追加
Lambda側でCORS HTTPヘッダーを追加

上記の処理を行いHTTPヘッダーに上記文字列の確認ができれば、Ajaxなどからデータ取得できます。