Amazon DynamoDB テーブルを作成する
処理の受付、ステータス管理、結果の格納にはデータベースを利用してデータを管理します。
今回利用するAmazon DynamoDBは、NoSQLデータベースサービスです。
マネジメントコンソールからDynamoDBのサービスを探します。
「テーブルの作成」をクリックします。
テーブル名を入力します。ここでは「point-cloud」としています。
パーティションキーに「id」を入力します。
「テーブルの作成」をクリックします。
テーブルが作成されました。
Lambdaを作成する
マネジメントコンソールからLambdaのサービスを探します。
Lambdaのダッシュボードページで「関数の作成」をクリックします。
関数の作成ページで「一から作成」を選択します。
基本的な情報で関数名を入力します。ここでは「pointCloudFunction」としています。
ランタイムはNode.js 20.xを選択します。
「関数の作成」をクリックします。
関数が作成され、関数のページに遷移しました。
コードソースに以下の内容を記述し、「Deploy」をクリックします。
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import {
DynamoDBDocumentClient,
ScanCommand,
PutCommand,
GetCommand,
DeleteCommand,
} from "@aws-sdk/lib-dynamodb";
import crypto from "crypto";
import { ECSClient, RunTaskCommand } from '@aws-sdk/client-ecs';
const client = new DynamoDBClient({});
const dynamo = DynamoDBDocumentClient.from(client);
const tableName = "point-cloud";
export const handler = async (event, context) => {
let body;
let statusCode = 200;
let requestJson;
let task_id;
const headers = {
"Content-Type": "application/json",
};
try {
switch (event.routeKey) {
case "POST /pointcloud":
const acceptedAt = new Date();
const acceptedAtUtc = acceptedAt.toUTCString();
requestJson = JSON.parse(event.body);
task_id = crypto.randomBytes(16).toString("hex").substring(0, 16)
await dynamo.send(
new PutCommand({
TableName: tableName,
Item: {
id: task_id,
status: "IN_PROGRESS",
accepted_at: acceptedAtUtc,
started_at: null,
finished_at: null,
result: null
},
})
);
body = {
task_id: task_id
};
const ecs = new ECSClient({region: process.env.AWS_REGION})
const ecsParams = {
cluster: process.env.AWS_ECS_CLUSTER,
taskDefinition: process.env.AWS_ECS_TASK_DEFINITION,
count: 1,
launchType: "FARGATE",
networkConfiguration: {
awsvpcConfiguration: {
subnets: process.env.AWS_ECS_SUBNET.split(","),
securityGroups: process.env.AWS_ECS_SECURITY_GROUP.split(","),
}
},
overrides: {
containerOverrides: [
{
name: process.env.AWS_ECS_CONTAINER_NAME,
environment: [
{name:"DOWNLOAD_URL", value: requestJson.download_url},
{name:"FILE_NAME", value: requestJson.file_name},
{name:"CC_OPTION", value: requestJson.command},
{name:"IMAGE_UPLOAD_API_URL", value: process.env.IMAGE_UPLOAD_API_URL},
{name:"TASK_ID", value: task_id},
{name:"POINT_CLOUD_API_URL", value: process.env.POINT_CLOUD_API_URL},
]
}
]
}
}
console.log(JSON.stringify(ecsParams))
try {
await ecs.send(new RunTaskCommand(ecsParams))
}
catch(err){
console.log(err.message)
const response = {
statusCode:500,
body: JSON.stringify({
error:{
message: "internal server error"
}
})
}
return response
}
break;
case "PUT /pointcloud/tasks/{id}":
const changedAt = new Date();
const changedAtUtc = changedAt.toUTCString();
requestJson = JSON.parse(event.body);
task_id = event.pathParameters.id;
const result_id = crypto.randomBytes(16).toString("hex").substring(0, 16)
body = await dynamo.send(
new GetCommand({
TableName: tableName,
Key: {
id: task_id,
},
})
);
body = body.Item;
switch (requestJson.type) {
case "start":
await dynamo.send(
new PutCommand({
TableName: tableName,
Item: {
id: task_id,
status: "IN_PROGRESS",
accepted_at: body.accepted_at,
started_at: changedAtUtc,
finished_at: null,
result: null
},
})
);
break;
case "finish":
await dynamo.send(
new PutCommand({
TableName: tableName,
Item: {
id: task_id,
status: "SUCCEEDED",
accepted_at: body.accepted_at,
started_at: body.started_at,
finished_at: changedAtUtc,
result: {
result_id: result_id
}
},
})
);
await dynamo.send(
new PutCommand({
TableName: tableName,
Item: {
id: result_id,
download_url: "https://prd-sh-point-cloud.s3.ap-northeast-1.amazonaws.com/" + requestJson.path
},
})
);
break;
}
break;
case "GET /pointcloud/tasks/{id}":
body = await dynamo.send(
new GetCommand({
TableName: tableName,
Key: {
id: event.pathParameters.id,
},
})
);
body = body.Item;
break;
case "GET /pointcloud/results/{id}":
body = await dynamo.send(
new GetCommand({
TableName: tableName,
Key: {
id: event.pathParameters.id,
},
})
);
body = body.Item;
break;
default:
throw new Error(`Unsupported route: "${event.routeKey}"`);
}
} catch (err) {
statusCode = 400;
body = err.message;
} finally {
body = JSON.stringify(body);
}
return {
statusCode,
body,
headers,
};
};
設定→アクセス制限の順にクリックします。
実行ロールのロール名に表示されているリンクをクリックします。
Identity and Access Management (IAM)のロールページに遷移します。
許可ポリシーの「許可を追加」をクリックし「ポリシーをアタッチ」を選択します。
その他の許可ポリシーの検索フォームに「Dynamo」と入力します。
ポリシー名「AmazonDynamoDBFullAccess」の左のチェックを入れ「許可を追加」をクリックします。
ポリシーがロールにアタッチされました。
許可ポリシーに「AmazonS3FullAccess」が含まれています。
再度、許可ポリシーの「許可を追加」をクリックし「ポリシーをアタッチ」を選択します。
その他の許可ポリシーの検索フォームに「ECS」と入力します。
ポリシー名「AmazonECS_FullAccess」の左のチェックを入れ「許可を追加」をクリックします。
ポリシーがロールにアタッチされました。
許可ポリシーに「AmazonECS_FullAccess」が含まれています。
Lambdaのページに戻ります。
設定タブのメニューから環境変数ページに遷移します。
「編集」をクリックします
環境変数の編集で以下のように設定します。
| キー | 値 |
| AWS_ECS_CLUSTER | ECSのクラスターのARN |
| AWS_ECS_CONTAINER_NAME | point-cloud |
| AWS_ECS_SECURITY_GROUP | デフォルトのセキュリティグループID |
| AWS_ECS_SUBNET | デフォルトのサブネットID(カンマ区切り) |
| AWS_ECS_TASK_DEFINITION | ECSのタスク定義のARN |
| POINT_CLOUD_API_URL | 作成した点群処理APIのURL |
| IMAGE_UPLOAD_API_URL | 作成した画像アップロードAPIのURL |
これで、Lambdaの作成は完了となります。
API Gatewayを作成する
マネジメントコンソールからAPI Gatewayのサービスを探します。
API Gatewayのページへ移動し、「APIを作成」をクリックします。
APIタイプを選択では、「HTTP API」を選択し、「構築」をクリックします。
「REST API を作成」の画面に遷移します。
API名を入力します。ここでは「」としています。
「確認して作成」をクリックします。
「作成」をクリックします。
APIが作成されルートページに遷移します。
ルートの「作成」をクリックします。
「ルートの作成」の画面に遷移します。
左側の「メソッド」はPOSTを選択し、右側のパスは「/pointcloud」と入力します。
「作成」をクリックします。
ルートが追加されました。
「POST」を選択し「統合をアタッチする」をクリックします。
「統合を作成してアタッチ」をクリックします。
統合タイプは「Lambda関数」を選択します。
統合の詳細でLambda関数の選択ができるようになるので、作成したLambda関数を指定します。
「作成」をクリックします
統合がルートにアタッチされました。
以下のメソッドとルートで統合のアタッチを繰り返します。
アタッチする統合のLambda関数は全て同じです。
| メソッド | ルート |
| GET | /pointcloud/tasks/{id} |
| PUT | /pointcloud/tasks/{id} |
| GET | /pointcloud/results/{id} |
メニューのStagesからステージページに遷移します。
ステージの詳細の「URL を呼び出す」に表示されているURLがAPIのURLになります。