

# サンプルアプリケーションとパターンの使用開始
<a name="example-apps"></a>

次のリソースを使用すると、一般的な Lambda ユースケースを実装するサーバーレスアプリケーションをすばやく作成およびデプロイできます。アプリケーションの例ごとに、AWS マネジメントコンソール を使用してリソースを手動で作成および設定するか、AWS Serverless Application Model を使用して IaC でリソースをデプロイする手順を示します。コンソールの手順に従って、各アプリケーションに個々の AWS リソースの設定について詳細を確認するか、AWS SAM を使用して本番環境と同じようにリソースをすばやくデプロイします。

## ファイル処理
<a name="examples-apps-file"></a>
+ **[PDF 暗号化アプリケーション](file-processing-app.md)**: Amazon Simple Storage Service バケットにアップロードされた PDF ファイルを暗号化し、別のバケットに保存するサーバーレスアプリケーションを作成します。これは、アップロード時に機密文書を保護するのに役立ちます。
+ **[イメージ分析アプリケーション](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-example-s3.html)**:ドキュメント処理、コンテンツモデレーション、自動イメージ分析に役立つ Amazon Rekognition を使用して画像からテキストを抽出するサーバーレスアプリケーションを作成します。

## データベース統合
<a name="examples-apps-database"></a>
+ **[Queue-to-Database アプリケーション](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-lambda-tutorial.html)**: ユーザー登録の処理や注文の送信の処理に役立つ、Amazon RDS データベースにキューメッセージを書き込むサーバーレスアプリケーションを作成します。
+ **[データベースイベントハンドラー](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-example-ddb.html)**: 監査ログ記録、データレプリケーション、自動ワークフローに役立つ、Amazon DynamoDB テーブルの変更に応答するサーバーレスアプリケーションを作成します。

## スケジュールされたタスク
<a name="examples-apps-scheduled"></a>
+ **[データベースメンテナンスアプリケーション](scheduled-task-app.md)**: cron スケジュールを使用して Amazon DynamoDB テーブルから 12 か月以上経過したエントリを自動的に削除するサーバーレスアプリケーションを作成します。これは、データベースの自動メンテナンスとデータライフサイクル管理に役立ちます。
+ **[Lambda 関数の EventBridge スケジュールルールを作成する](https://docs.aws.amazon.com/eventbridge/latest/userguide/run-lambda-schedule.html)**: EventBridge のルールにスケジュールされた式を使用して、時間指定のスケジュールで Lambda 関数をトリガーします。この形式では、cron 構文を使用して 1 分単位で設定できます。

## 長時間のワークフロー
<a name="examples-apps-workflows"></a>
+ **[注文処理アプリケーション](order-processing-app.md)**: 支払い処理、インベントリ確認、配送調整など、複雑な注文履行を処理する耐久性のある関数を使用して、サーバーレスアプリケーションを作成します。この例では、状態を維持しながら長期間実行できるワークフローを構築する方法が示されます。

## その他のリソース
<a name="examples-apps-additional-resources"></a>

Lambda とサーバーレスアプリケーション開発についての詳細は、次のリソースを確認してください。
+ **[Serverless Land](https://serverlessland.com/)**: サーバーレスアプリケーションを構築する際に、すぐに活用できるパターンのライブラリ。これにより、開発者は Lambda、API Gateway、EventBridge などの AWS サービスを使用してアプリケーションをより速く作成できます。このサイトには構築済みのソリューションとベストプラクティスが用意されているため、サーバーレスシステムの開発が容易になります。
+ **[Lambda サンプルアプリケーション](https://docs.aws.amazon.com/lambda/latest/dg/lambda-samples.html)**: このガイドの GitHub リポジトリで利用可能なアプリケーション。これらのサンプルは、さまざまな言語と AWS サービスの使用方法を示しています。各サンプルアプリケーションには、デプロイとクリーンアップを容易にするスクリプトとサポート リソースが含まれています。
+ **[AWS SDK を使用した Lambda のコード例](https://docs.aws.amazon.com/lambda/latest/dg/service_code_examples.html)**: AWSソフトウェア開発キット (SDK) で Lambda を使用する方法を示す例。これらの例には、基本、アクション、シナリオ、AWS コミュニティへの貢献が含まれます。例としては、基本的な操作、個々のサービス関数、複数の関数または AWS サービスを使用する特定のタスクが含まれます。

# サーバーレスファイル処理アプリケーションを作成する
<a name="file-processing-app"></a>

Lambda の最も一般的なユースケースの 1 つは、ファイル処理タスクを実行することです。例えば、Lambda 関数を使用して、HTML ファイルまたは画像から PDF ファイルを自動的に作成したり、ユーザーが画像をアップロードしたときにサムネイルを作成したりできます。

この例では、PDF ファイルが Amazon Simple Storage Service (Amazon S3) バケットにアップロードされると自動的に暗号化されるアプリケーションを作成します。このアプリを実装するには、以下のリソースを作成する必要があります。
+ ユーザーが PDF ファイルをアップロードするための S3 バケット
+ アップロードされたファイルを読み取り、暗号化されたパスワードで保護されたバージョンのファイルを作成する Python の Lambda 関数
+ Lambda が暗号化されたファイルに保存するための 2 番目の S3 バケット

また、AWS Identity and Access Management (IAM) ポリシーを作成して、S3 バケットで読み取りおよび書き込みオペレーションを実行するアクセス許可を Lambda 関数に付与します。

![\[\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/ExampleApps/file_process_resources.png)


**ヒント**  
Lambda を初めて使用する場合は、このサンプルアプリを作成する前にチュートリアル [最初の Lambda 関数を作成する](getting-started.md) から始めることをお勧めします。

AWS マネジメントコンソール または AWS Command Line Interface (AWS CLI) を使用してリソースを作成して設定することで、アプリケーションを手動でデプロイできます。AWS Serverless Application Model (AWS SAM) を使用してアプリケーションをデプロイすることもできます。AWS SAM は、Infrastructure as Code (IaC) ツールです。IaC では、リソースを手動で作成するのではなく、コードに定義して自動的にデプロイします。

このサンプルアプリケーションをデプロイする前に、IaC で Lambda を使用する方法の詳細については、「[Lambda と Infrastructure as code (IaC) の使用](foundation-iac.md)」を参照してください。

## Lambda 関数のソースコードファイルを作成する
<a name="file-processing-app-download"></a>

プロジェクトディレクトリに次のファイルを作成します。
+ `lambda_function.py` - ファイル暗号化を実行する Lambda 関数の Python 関数コード
+ `requirements.txt` - Python 関数コードに必要な依存関係を定義するマニフェストファイル

以下のセクションを展開してコードを表示し、各ファイルの役割の詳細を確認してください。ローカルマシンにファイルを作成するには、以下のコードをコピーして貼り付けるか、[aws-lambda-developer-guide GitHub レポジトリ](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/file-processing-python)からファイルをダウンロードします。

### Python 関数コード
<a name="file-processing-app-function-code"></a>

次のコードをコピーし、`lambda_function.py` という名前のファイルに貼り付けます。

```
from pypdf import PdfReader, PdfWriter
import uuid
import os
from urllib.parse import unquote_plus
import boto3

# Create the S3 client to download and upload objects from S3
s3_client = boto3.client('s3')

def lambda_handler(event, context):
    # Iterate over the S3 event object and get the key for all uploaded files
    for record in event['Records']:
        bucket = record['s3']['bucket']['name']
        key = unquote_plus(record['s3']['object']['key']) # Decode the S3 object key to remove any URL-encoded characters
        download_path = f'/tmp/{uuid.uuid4()}.pdf' # Create a path in the Lambda tmp directory to save the file to 
        upload_path = f'/tmp/converted-{uuid.uuid4()}.pdf' # Create another path to save the encrypted file to
        
        # If the file is a PDF, encrypt it and upload it to the destination S3 bucket
        if key.lower().endswith('.pdf'):
            s3_client.download_file(bucket, key, download_path)
            encrypt_pdf(download_path, upload_path)
            encrypted_key = add_encrypted_suffix(key)
            s3_client.upload_file(upload_path, f'{bucket}-encrypted', encrypted_key)

# Define the function to encrypt the PDF file with a password
def encrypt_pdf(file_path, encrypted_file_path):
    reader = PdfReader(file_path)
    writer = PdfWriter()
    
    for page in reader.pages:
        writer.add_page(page)

    # Add a password to the new PDF
    writer.encrypt("my-secret-password")

    # Save the new PDF to a file
    with open(encrypted_file_path, "wb") as file:
        writer.write(file)

# Define a function to add a suffix to the original filename after encryption
def add_encrypted_suffix(original_key):
    filename, extension = original_key.rsplit('.', 1)
    return f'{filename}_encrypted.{extension}'
```

**注記**  
このサンプルコードでは、暗号化されたファイル (`my-secret-password`) のパスワードが関数コードにハードコードされます。本番環境のアプリケーションでは、関数コードにパスワードなどの機密情報を含めないでください。代わりに、[AWS Secrets Manager シークレットを作成](https://docs.aws.amazon.com/secretsmanager/latest/userguide/create_secret.html)し、[AWS Parameters and Secrets Lambda 拡張機能を使用](with-secrets-manager.md)して Lambda 関数の認証情報を取得します。

Python 関数コードには 3 つの関数が含まれています。1 つは関数が呼び出されたときに Lambda が実行する[ハンドラー関数](python-handler.md)、他の 2 つは PDF 暗号化を実行するためにハンドラーが呼び出す `add_encrypted_suffix` と `encrypt_pdf` という名前のそれぞれ独立した関数です。

関数が Amazon S3 によって呼び出されると、Lambda は呼び出しの原因となったイベントの詳細を含む JSON 形式の*イベント*引数を関数に渡します。この場合、情報には S3 バケットの名前と、アップロードされたファイルのオブジェクトキーが含まれます。Amazon S3 のイベントオブジェクトの形式の詳細については、「[Lambda を使用した Amazon S3 イベント通知の処理](with-s3.md)」を参照してください。

次に、関数は AWS SDK for Python (Boto3) を使用して、イベントオブジェクトで指定された PDF ファイルをローカル一時ストレージディレクトリにダウンロードしてから、[https://pypi.org/project/pypdf/](https://pypi.org/project/pypdf/) ライブラリを使用して暗号化します。

最後に、この関数は Boto3 SDK を使用して暗号化されたファイルを S3 送信先バケットに保存します。

### `requirements.txt` マニフェストファイル
<a name="file-processing-app-dependencies"></a>

次のコードをコピーし、`requirements.txt` という名前のファイルに貼り付けます。

```
boto3
pypdf
```

この例では、関数コードには、標準の Python ライブラリに含まれていない依存関係が 2 つしかありません。SDK for Python (Boto3) と、関数が PDF 暗号化の実行に使用する `pypdf` パッケージです。

**注記**  
SDK for Python (Boto3) のバージョンは Lambda ランタイムの一部として含まれているため、Boto3 を関数のデプロイパッケージに追加せずにコードが実行されます。ただし、関数の依存関係を完全に制御し、バージョン不一致による問題を回避するには、Python のベストプラクティスとして、関数のデプロイパッケージにすべての関数の依存関係を含めることをお勧めします。詳細については、「[Python でのランタイム依存関係](python-package.md#python-package-dependencies)」を参照してください。

## アプリをデプロイする
<a name="file-processing-app-deploy"></a>

このサンプルアプリケーションのリソースは、手動または AWS SAM を使用して作成およびデプロイできます。実稼働環境では、AWS SAM のような IaC ツールを使用して、手動プロセスを使用せずにサーバーレスアプリケーション全体を迅速かつ繰り返しデプロイすることをお勧めします。

### リソースを手動でデプロイする
<a name="file-processing-app-deploy-manual"></a>

アプリを手動でデプロイするには:
+ ソースと送信先の Amazon S3 バケットを作成する
+ PDF ファイルを暗号化し、暗号化されたバージョンを S3 バケットに保存する Lambda 関数を作成する
+ オブジェクトがソースバケットにアップロードされたときに、関数を呼び出す Lambda トリガーを設定する

開始する前に、ビルドマシンに [Python](https://www.python.org/downloads/) がインストールされていることを確認してください。

#### 2 つの S3 バケットを作成する
<a name="file-processing-app-deploy-manual-create-buckets"></a>

まず、2 つの S3 バケットを作成します。1 つ目のバケットは、PDF ファイルをアップロードするソース バケットです。2 つ目のバケットは、関数を呼び出すときに暗号化されたファイルを保存するために Lambda が使用するバケットです。

------
#### [ Console ]

**S3 バケットを作成するには (コンソール)**

1. Amazon S3 コンソールの [[汎用バケット]](https://console.aws.amazon.com/s3/buckets) ページを開きます。

1. 住まいの地域に最も近い AWS リージョン を選択してください。画面上部にあるドロップダウンリストを使用して、リージョンを変更できます。  
![\[\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/console_region_select.png)

1. **[バケットを作成する]** を選択します。

1. **[全般設定]** で、次の操作を行います。

   1. **[バケットタイプ]** で、**[汎用]** が選択されていることを確認してください。

   1. **[バケット名]** には、Amazon S3 [バケットの命名規則](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html)を満たすグローバルに一意な名前を入力します。バケット名は、小文字、数字、ドット (.)、およびハイフン (-) のみで構成できます。

1. 他のすべてのオプションはデフォルト設定値のままにしておき、**[バケットの作成]** を選択します。

1. ステップ 1 ～ 4 を繰り返して、送信先のバケットを作成します。**[バケット名]** には `amzn-s3-demo-bucket-encrypted` と入力します。`amzn-s3-demo-bucket` は先ほど作成したソース元バケットの名前です。

------
#### [ AWS CLI ]

開始する前に、ビルドマシンに [AWS CLI がインストールされている](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)ことを確認してください。

**Amazon S3 バケットを作成する方法 (AWS CLI)**

1. 次の CLI コマンドを実行して、ソース元のバケットを作成します。バケットに付ける名前は、グローバルに一意で、Amazon S3 [バケットの命名規則](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html)に従ったものである必要があります。名前には、小文字、数字、ドット (.)、およびハイフン (-) のみを使用できます。`region` および `LocationConstraint` については、お住まいの地域に最も近い [AWS リージョン](https://docs.aws.amazon.com/general/latest/gr/lambda-service.html) を選択してください。

   ```
   aws s3api create-bucket --bucket amzn-s3-demo-bucket --region us-east-2 \
   --create-bucket-configuration LocationConstraint=us-east-2
   ```

   チュートリアルの後半では、ソース元バケットと同じ AWS リージョン で Lambda 関数を作成する必要があるため、選択したリージョンを書き留めておいてください。

1. 次のコマンドを実行して、送信先のバケットを作成します。バケット名には `amzn-s3-demo-bucket-encrypted` を使用する必要があります。`amzn-s3-demo-bucket` はステップ 1 で作成したソース元バケットの名前です。`region` および `LocationConstraint` については、ソース元バケットを作成するときに使用したものと同じ AWS リージョン を選択してください。

   ```
   aws s3api create-bucket --bucket amzn-s3-demo-bucket-encrypted --region us-east-2 \
   --create-bucket-configuration LocationConstraint=us-east-2
   ```

------

#### 実行ロールを作成する
<a name="file-processing-app-deploy-manual-create-execution-role"></a>

実行ロールとは、AWS のサービス とリソースにアクセスする許可を Lambda 関数に付与する IAM ロールです。関数に Amazon S3 への読み取りおよび書き込みアクセスを許可するには、[AWS 管理ポリシー](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html#aws-managed-policies) `AmazonS3FullAccess` をアタッチします。

------
#### [ Console ]

**実行ロールを作成して `AmazonS3FullAccess` 管理ポリシーをアタッチするには (コンソール)**

1. IAM コンソールの [[ロール]](https://console.aws.amazon.com/iam/home/roles) ページを開きます。

1. [**ロールの作成**] を選択してください。

1. **[信頼されたエンティティタイプ]** で **[AWS サービス]** を選択し、**[ユースケース]** で **[Lambda]** を選択します。

1. [**次へ**] を選択します。

1. 次の手順を実行して `AmazonS3FullAccess` 管理ポリシーを追加します。

   1. **[許可ポリシー]** で、検索ボックスに **AmazonS3FullAccess** と入力します。

   1. ポリシーの横にあるチェックボックスを選択します。

   1. [**次へ**] を選択します。

1. **[ロールの詳細]** の **[ロール名]** には **LambdaS3Role** を入力します。

1. **[ロールの作成]** を選択します。

------
#### [ AWS CLI ]

**実行ロールを作成して `AmazonS3FullAccess` 管理ポリシー (AWS CLI) をアタッチするには**

1. 次の JSON を `trust-policy.json` という名のファイルに保存します。この信頼ポリシーは、AWS Security Token Service (AWS STS) `AssumeRole` アクションを呼び出すサービスプリンシパルの `lambda.amazonaws.com` アクセス許可を付与することで、Lambda がロールのアクセス許可を使用できるようにします。  
****  

   ```
   {
     "Version":"2012-10-17",		 	 	 
     "Statement": [
       {
         "Effect": "Allow",
         "Principal": {
           "Service": "lambda.amazonaws.com"
         },
         "Action": "sts:AssumeRole"
       }
     ]
   }
   ```

1. JSON 信頼ポリシードキュメントを保存したディレクトリから、次の CLI コマンドを実行して実行ロールを作成します。

   ```
   aws iam create-role --role-name LambdaS3Role --assume-role-policy-document file://trust-policy.json
   ```

1. `AmazonS3FullAccess` 管理ポリシーをアタッチするには、次の CLI コマンドを実行します。

   ```
   aws iam attach-role-policy --role-name LambdaS3Role --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess
   ```

------

#### 関数デプロイパッケージを作成する
<a name="file-processing-app-deploy-manual-create-function-package"></a>

関数を作成するには、関数コードおよびその依存関係を含む*デプロイパッケージ*を作成します。このアプリケーションでは、関数コードは PDF 暗号化に別のライブラリを使用します。

**デプロイパッケージを作成するには**

1. 以前に GitHub から作成またはダウンロードした `lambda_function.py` および `requirements.txt` ファイルを含むプロジェクトディレクトリに移動し、`package` という名前の新しいディレクトリを作成します。

1. 次のコマンドを実行して、 `package` ディレクトリの `requirements.txt` ファイルで指定された依存関係をインストールします。

   ```
   pip install -r requirements.txt --target ./package/
   ```

1. アプリケーション コードとその依存関係を含む .zip ファイルを作成します。Linux または MacOS では、コマンドラインインターフェイスから次のコマンドを実行します。

   ```
   cd package
   zip -r ../lambda_function.zip .
   cd ..
   zip lambda_function.zip lambda_function.py
   ```

    Windows では、任意の zip ツールを使用して、`lambda_function.zip` ファイルを作成します。`lambda_function.py` ファイルと依存関係が含まれるフォルダは、.zip ファイルのルートにインストールする必要があります。

また、Python 仮想環境を使用してデプロイパッケージを作成することもできます。「[Python Lambda 関数で .zip ファイルアーカイブを使用する](python-package.md)」を参照してください。

#### Lambda 関数を作成する
<a name="file-processing-app-deploy-manual-createfunction"></a>

これで、前のステップで作成したデプロイパッケージを使用して Lambda 関数をデプロイします。

------
#### [ Console ]

**関数を作成するには (コンソール)**

コンソールを使用して Lambda 関数を作成するには、まず「Hello world」コードが含まれるベーシックな関数を作成します。次に、前のステップで作成した .zip ファイルをアップロードして、、このコードを自身で作成した関数コードへと置き換えます。

サイズの大きい PDF ファイルを暗号化するときに関数がタイムアウトしないようにするには、関数のメモリとタイムアウトの設定が必要です。また、関数のログ形式を JSON に設定します。提供されたテストスクリプトを使用するときは、CloudWatch Logs から関数の呼び出しステータスを読み取って呼び出しが成功したことを確認するために、JSON 形式のログを設定する必要があります。

1. Lambda コンソールの [[関数]](https://console.aws.amazon.com/lambda/home#/functions) ページを開きます。

1. S3 バケットを作成したときと同じ AWS リージョン で操作していることを確認してください。画面上部にあるドロップダウンリストを使用して、リージョンを変更できます。  
![\[\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/console_region_select.png)

1. **関数の作成** を選択します。

1. **Author from scratch** を選択します。

1. **基本的な情報** で、以下の作業を行います。

   1. **[関数名]** に「`EncryptPDF`」と入力します。

   1. **ランタイム** には、**[Python 3.12]** を選択します。

   1. **[アーキテクチャ]** で **[x86\$164]** を選択します。

1. 次の手順を実行して、前のステップで作成した実行ロールをアタッチします。

   1. **[デフォルト実行ロールの変更]** セクションを展開します。

   1. **[既存のロールを使用]** を選択します。

   1. **[既存のロール]** で、ロール (`LambdaS3Role`) を選択します。

1. [**関数の作成**] を選択してください。

**関数コードをアップロードする方法 (コンソール)**

1. **[コードソース]** ペインで、**[アップロード元]** をクリックします。

1. **[.zip ファイル]** をクリックします。

1. **アップロード** を選択します。

1. ファイルセレクターで .zip ファイルを選択し、**[開く]** を選択します。

1. **[保存]** を選択します。

**関数のメモリとタイムアウトを設定するには (コンソール）**

1. 関数の **[設定]** タブを選択します。

1. **[一般設定]** ペインで、**[編集]** を選択します。

1. **[メモリ]** を 256 MB に設定し、**[タイムアウト]**を 15 秒に設定します。

1. **[保存]** を選択します。

**ログ形式を設定するには (コンソール）**

1. 関数の **[設定]** タブを選択します。

1. **[モニタリングおよび運用ツール]** を選択します。

1. **[ログ記録設定]** ペインで、**[編集]** を選択します。

1. **[ログ記録設定]** で、**[JSON]**を選択します。

1. **[保存]** を選択します。

------
#### [ AWS CLI ]

**関数を作成する方法 (AWS CLI)**
+ `lambda_function.zip` ファイルを含むディレクトリから次のコマンドを実行します。`region` パラメータの場合は、`us-east-2` を S3 バケットを作成したリージョンに置き換えます。

  ```
  aws lambda create-function --function-name EncryptPDF \
  --zip-file fileb://lambda_function.zip --handler lambda_function.lambda_handler \
  --runtime python3.12 --timeout 15 --memory-size 256 \
  --role arn:aws:iam::123456789012:role/LambdaS3Role --region us-east-2 \
  --logging-config LogFormat=JSON
  ```

------

#### 関数を呼び出すように Amazon S3 トリガーを設定する
<a name="file-processing-app-deploy-manual-configure-s3-trigger"></a>

ファイルをソース元のバケットにアップロードするときに Lambda 関数が実行されるようにするには、関数のトリガーを設定する必要があります。Amazon S3 トリガーは、コンソールまたは AWS CLI を使用して設定できます。

**重要**  
この手順では、オブジェクトが S3 バケット内に作成されるたびに、関数を呼び出すようにバケットを設定します。この設定は、ソース元バケットのみで行うようにしてください。Lambda 関数が自身を呼び出した同じバケットにオブジェクトを作成する場合、関数が[連続的にループして呼び出される](https://serverlessland.com/content/service/lambda/guides/aws-lambda-operator-guide/recursive-runaway)可能性があります。その結果、予期しない請求がお客様の AWS アカウント に請求される可能性があります。

------
#### [ Console ]

**Amazon S3 トリガーを設定する方法 (コンソール)**

1. Lambda コンソールの [[関数]](https://console.aws.amazon.com/lambda/home#/functions) ページを開き、関数を選択します (`EncryptPDF`)。

1. **[トリガーを追加]** を選択します。

1. **[S3]** を選択します。

1. **[バケット]** で、ソース元のバケットを選択します。

1. **[イベントタイプ]** で、**[すべてのオブジェクト作成イベント]** を選択します。

1. **[再帰呼び出し]** でチェックボックスをオンにすると、入力と出力に同じ S3 バケットを使用することは推奨されないことを認識できます。Lambda の再帰呼び出しパターンについて詳しくは、Serverless Land の「[Lambda 関数が暴走する原因となる再帰パターン](https://serverlessland.com/content/service/lambda/guides/aws-lambda-operator-guide/recursive-runaway)」を参照してください。

1. **[Add]** (追加) を選択します。

   Lambda コンソールを使用してトリガーを作成すると、Lambda は[リソースベースのポリシー](https://docs.aws.amazon.com/lambda/latest/dg/access-control-resource-based.html)を自動的に作成し、選択したサービスに関数を呼び出すアクセス許可を付与します。

------
#### [ AWS CLI ]

**Amazon S3 トリガーを設定する方法 (AWS CLI)**

1. ファイルを追加するときに Amazon S3 のソースバケットが関数を呼び出すことを許可する [[リソースベースのポリシー]](https://docs.aws.amazon.com/lambda/latest/dg/access-control-resource-based.html) を関数に追加します。リソースベースのポリシーステートメントが、他の AWS のサービス に関数を呼び出す権限を付与します。Amazon S3 に関数を呼び出す権限を付与するには、次の CLI コマンドを実行します。`source-account` パラメータは必ず自分自身の AWS アカウント ID に置き換えて、自分自身のソース元バケット名を使用するようにしてください。

   ```
   aws lambda add-permission --function-name EncryptPDF \
   --principal s3.amazonaws.com --statement-id s3invoke --action "lambda:InvokeFunction" \
   --source-arn arn:aws:s3:::amzn-s3-demo-bucket \
   --source-account 123456789012
   ```

   このコマンドで定義するポリシーにより、Amazon S3 はソース元バケットでアクションが発生した場合にのみ、関数を呼び出すことができるようになります。
**注記**  
S3 バケットの名前はグローバルに一意ですが、リソースベースのポリシーを使用する場合には、バケットがアカウントに属していなければならないことを指定するのがベストプラクティスです。これは、バケットを削除したときに、別の AWS アカウント が同じ Amazon リソースネーム (ARN) でバケットを作成する可能性があるからです。

1. 次の JSON を `notification.json` という名のファイルに保存します。この JSON をソースバケットに適用すると、新しいオブジェクトが追加されるたびに Lambda 関数に通知を送信するようにバケットが設定されます。Lambda 関数 ARN の AWS アカウント 番号と AWS リージョン を、自分自身のアカウント番号とリージョンへと置き換えます。

   ```
   {
   "LambdaFunctionConfigurations": [
       {
         "Id": "EncryptPDFEventConfiguration",
         "LambdaFunctionArn": "arn:aws:lambda:us-east-2:123456789012:function:EncryptPDF",
         "Events": [ "s3:ObjectCreated:Put" ]
       }
     ]
   }
   ```

1. 次の CLI コマンドを実行して、JSON ファイル内に作成した通知設定をソース元のバケットに適用します。`amzn-s3-demo-bucket` を自分自身のソース元バケットの名前へと置き換えます。

   ```
   aws s3api put-bucket-notification-configuration --bucket amzn-s3-demo-bucket \
   --notification-configuration file://notification.json
   ```

   `put-bucket-notification-configuration` コマンドと `notification-configuration` オプションの詳細については、「*AWS CLI コマンドリファレンス*」の「[put-bucket-notification-configuration](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3api/put-bucket-notification-configuration.html)」を参照してください。

------

### AWS SAM を使用してリソースをデプロイする
<a name="file-processing-app-deploy-sam"></a>

開始する前に、[Docker](https://docs.docker.com/get-docker/) と [AWS SAMCLI の最新バージョン](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html)がビルドマシンにインストールされていることを確認してください。

1. プロジェクトディレクトリで、次のコードをコピーして `template.yaml` という名前のファイルに貼り付けます。プレースホルダーバケット名を置き換えます。
   + ソースバケットの場合は、`amzn-s3-demo-bucket` を [S3 バケットの命名規則](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html)に準拠した任意の名前に置き換えます。
   + レプリケート先バケットの場合は、`amzn-s3-demo-bucket-encrypted` を `<source-bucket-name>-encrypted` に置き換えます。この `<source-bucket>` はレプリケート元バケットに選択した名前です。

   ```
   AWSTemplateFormatVersion: '2010-09-09'
   Transform: AWS::Serverless-2016-10-31
   
   Resources:
     EncryptPDFFunction:
       Type: AWS::Serverless::Function
       Properties:
         FunctionName: EncryptPDF
         Architectures: [x86_64]
         CodeUri: ./
         Handler: lambda_function.lambda_handler
         Runtime: python3.12
         Timeout: 15
         MemorySize: 256
         LoggingConfig:
           LogFormat: JSON
         Policies:
           - AmazonS3FullAccess
         Events:
           S3Event:
             Type: S3
             Properties:
               Bucket: !Ref PDFSourceBucket
               Events: s3:ObjectCreated:*
   
     PDFSourceBucket:
       Type: AWS::S3::Bucket
       Properties:
         BucketName: amzn-s3-demo-bucket
   
     EncryptedPDFBucket:
       Type: AWS::S3::Bucket
       Properties:
         BucketName: amzn-s3-demo-bucket-encrypted
   ```

   AWS SAM テンプレートは、アプリケーション用に作成するリソースを定義します。この例では、テンプレートは `AWS::Serverless::Function` タイプを使用して Lambda 関数を定義し、`AWS::S3::Bucket` タイプを使用して 2 つの S3 バケットを定義します。テンプレートで指定されたバケット名はプレースホルダーです。AWS SAM を使用してアプリケーションをデプロイする前に、テンプレートを編集して、[S3 バケットの命名規則](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html)を満たすグローバルに一意の名前でバケットの名前を変更する必要があります。このステップについては、「[AWS SAM を使用してリソースをデプロイする](#file-processing-app-deploy-sam)」で詳しく説明します。

   Lambda 関数リソースの定義は、`S3Event` イベントプロパティを使用して関数のトリガーを設定します。このトリガーにより、ソースバケットにオブジェクトが作成されるたびに関数が呼び出されます。

   関数定義は、関数の[実行ロール](lambda-intro-execution-role.md)にアタッチする AWS Identity and Access Management (IAM) ポリシーも指定します。[AWS 管理ポリシー](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html#aws-managed-policies) `AmazonS3FullAccess` は、Amazon S3 へのオブジェクトの読み取りと書き込みに必要なアクセス許可を関数に付与します。

1. `template.yaml`、`lambda_function.py`、および `requirements.txt` ファイルを保存したディレクトリで、次のコマンドを実行します。

   ```
   sam build --use-container
   ```

   このコマンドによって、アプリケーションのビルドアーティファクトが収集され、それらをデプロイする場所を適切な形式で配置します。`--use-container` オプションを指定すると、Lambda のような Docker コンテナ内に関数がビルドされます。ここではこれを使用するため、ビルドを実行するためにローカルマシンに Python 3.12 をインストールする必要はありません。

   ビルドプロセス中に、AWS SAM はテンプレートの `CodeUri` プロパティで指定した場所で Lambda 関数コードを検索します。この場合、現在のディレクトリをロケーション (`./`) として指定しました。

   `requirements.txt` ファイルが存在する場合、AWS SAM はそれを使用して指定された依存関係を収集します。デフォルトでは、AWS SAM は関数コードと依存関係を含む .zip デプロイパッケージを作成します。[PackageType](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html#sam-function-packagetype) プロパティを使用して、関数をコンテナイメージとしてデプロイすることもできます。

1. アプリケーションをデプロイし、AWS SAM テンプレートで指定された Lambda リソースと Amazon S3 リソースを作成するには、次のコマンドを実行します。

   ```
   sam deploy --guided
   ```

   `--guided` フラグを使用すると、AWS SAM にデプロイプロセスの手順が示されます。このデプロイでは、Enter キーを押してデフォルトのオプションをそのまま使用してください。

デプロイプロセス中に、AWS SAM でお使いの AWS アカウントに次のリソースが作成されます。
+ `sam-app` という名前の CloudFormation[ スタック](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-whatis-concepts.html#cfn-concepts-stacks)
+ `EncryptPDF` という名前の Lambda 関数
+ `template.yaml` AWS SAM テンプレートファイルを編集したときに選択した名前の 2 つの S3 バケット
+ 名前形式 `sam-app-EncryptPDFFunctionRole-2qGaapHFWOQ8` の関数の IAM 実行ロール

AWS SAM がリソースの作成を完了すると、次のメッセージが表示されます。

```
Successfully created/updated stack - sam-app in us-east-2
```

## アプリケーションをテストする
<a name="file-processing-app-test"></a>

アプリをテストするには、PDF ファイルをソースバケットにアップロードし、Lambda が送信先バケットに暗号化されたバージョンのファイルを作成することを確認します。この例では、コンソールまたは AWS CLI を使用して手動でテストするか、提供されたテストスクリプトを使用してテストできます。

本番環境のアプリケーションでは、ユニットテストなどの従来のテスト方法や手法を使用して、Lambda 関数コードが正しく機能していることを確認できます。ベストプラクティスは、実際のクラウドベースのリソースとの統合テストを実行する、提供されているテストスクリプトのようなテストを実行することです。クラウド環境における統合テストでは、インフラストラクチャが適切にデプロイされ、イベントが期待どおりに異なるサービス間で流れることを確認します。詳細については[サーバーレス関数とアプリケーションをテストする方法](testing-guide.md)を参照してください。

### アプリケーションの手動テスト
<a name="file-processing-app-test-manual"></a>

Amazon S3 ソースバケットに PDF ファイルを追加することで、関数を手動でテストできます。ファイルをソースバケットに追加すると、Lambda 関数が自動的に呼び出され、ファイルの暗号化されたバージョンが送信先のバケットに保存されます。

------
#### [ Console ]

**ファイルをアップロードしてアプリケーションをテストするには (コンソール）**

1. PDF ファイルを S3 バケットにアップロードするには、次の手順を実行します。

   1. Amazon S3 コンソールの[[バケット]](https://console.aws.amazon.com/s3/buckets) ページを開き、ソース元のバケットを選択します。

   1. **アップロード** を選択します。

   1. **[ファイルを追加]** を選択し、ファイルセレクターを使用してアップロードする PDF ファイルを選択します。

   1. **[開く]**、**[アップロード]** の順に選択します。

1. 次の手順を実行して、Lambda が PDF ファイルの暗号化されたバージョンを送信先のバケットに保存したことを確認します。

   1. Amazon S3 コンソールの [[バケット]](https://console.aws.amazon.com/s3/buckets) ページに戻り、送信先バケットを選択します。

   1. **[オブジェクト]** ペインに、名前形式 `filename_encrypted.pdf` (`filename.pdf` はソースバケットにアップロードしたファイルの名前) のファイルが表示されます。暗号化された PDF をダウンロードするには、ファイルを選択し、**[ダウンロード]** を選択します。

   1. ダウンロードしたファイルを、Lambda 関数で保護されたパスワード (`my-secret-password`) で開くことができることを確認します。

------
#### [ AWS CLI ]

**ファイルをアップロードしてアプリケーションをテストするには (AWS CLI）**

1. アップロードする PDF ファイルが含まれるディレクトリから、次の CLI コマンドを実行します。`--bucket` パラメータをソース元バケットの名前に置き換えます。`--key` および `--body` パラメータには、テストファイルのファイル名を使用します。

   ```
   aws s3api put-object --bucket amzn-s3-demo-bucket --key test.pdf --body ./test.pdf
   ```

1. 関数によってファイルの暗号化されたバージョンが作成され、それが送信先の S3 バケットに保存されたことを確認します。`amzn-s3-demo-bucket-encrypted` を自分自身の送信先のバケットの名前へと置き換えて、次の CLI コマンドを実行します。

   ```
   aws s3api list-objects-v2 --bucket amzn-s3-demo-bucket-encrypted
   ```

   関数が正常に実行されると、以下に類似した出力が表示されます。送信先のバケットには、名前形式 `<your_test_file>_encrypted.pdf` のファイルが含まれている必要があります。`<your_test_file>` はアップロードしたファイル名です。

   ```
   {
       "Contents": [
           {
               "Key": "test_encrypted.pdf",
               "LastModified": "2023-06-07T00:15:50+00:00",
               "ETag": "\"7781a43e765a8301713f533d70968a1e\"",
               "Size": 2763,
               "StorageClass": "STANDARD"
           }
       ]
   }
   ```

1. Lambda が送信先のバケットに保存したファイルをダウンロードするには、次の CLI コマンドを実行します。`--bucket` パラメータを送信先のバケットの名前に置き換えます。`--key` パラメータには、ファイル名 `<your_test_file>_encrypted.pdf` を使用します。`<your_test_file>` はアップロードしたテストファイルの名前です。

   ```
   aws s3api get-object --bucket amzn-s3-demo-bucket-encrypted --key test_encrypted.pdf my_encrypted_file.pdf
   ```

   このコマンドは、ファイルを現在のディレクトリにダウンロードし、`my_encrypted_file.pdf` として保存します。

1. ダウンロードしたファイルを、Lambda 関数で保護されたパスワード (`my-secret-password`) で開くことができることを確認します。

------

### 自動スクリプトを使用したアプリケーションのテスト
<a name="file-processing-app-test-auto"></a>

プロジェクトディレクトリに次のファイルを作成します。
+ `test_pdf_encrypt.py` - アプリケーションの自動テストに使用できるテストスクリプト
+ `pytest.ini` - テストスクリプトの設定ファイル

以下のセクションを展開してコードを表示し、各ファイルの役割の詳細を確認してください。

#### 自動テストスクリプト
<a name="file-processing-app-test-script"></a>

次のコードをコピーし、`test_pdf_encrypt.py` という名前のファイルに貼り付けます。プレースホルダーバケット名は必ず置き換えてください。
+ `test_source_bucket_available` 関数で、`amzn-s3-demo-bucket` をソースバケットの名前に置き換えます。
+ `test_encrypted_file_in_bucket` 関数で、`amzn-s3-demo-bucket-encrypted` を `source-bucket-encrypted` に置き換えます。`source-bucket>` はソースバケットの名前です。
+ `cleanup` 関数で、`amzn-s3-demo-bucket` をソースバケットの名前に置き換え、`amzn-s3-demo-bucket-encrypted` を送信先バケットの名前に置き換えます。

```
import boto3
import json
import pytest
import time
import os

@pytest.fixture
def lambda_client():
    return boto3.client('lambda')
    
@pytest.fixture
def s3_client():
    return boto3.client('s3')

@pytest.fixture
def logs_client():
    return boto3.client('logs')

@pytest.fixture(scope='session')
def cleanup():
    # Create a new S3 client for cleanup
    s3_client = boto3.client('s3')

    yield
    # Cleanup code will be executed after all tests have finished

    # Delete test.pdf from the source bucket
    source_bucket = 'amzn-s3-demo-bucket'
    source_file_key = 'test.pdf'
    s3_client.delete_object(Bucket=source_bucket, Key=source_file_key)
    print(f"\nDeleted {source_file_key} from {source_bucket}")

    # Delete test_encrypted.pdf from the destination bucket
    destination_bucket = 'amzn-s3-demo-bucket-encrypted'
    destination_file_key = 'test_encrypted.pdf'
    s3_client.delete_object(Bucket=destination_bucket, Key=destination_file_key)
    print(f"Deleted {destination_file_key} from {destination_bucket}")
        

@pytest.mark.order(1)
def test_source_bucket_available(s3_client):
    s3_bucket_name = 'amzn-s3-demo-bucket'
    file_name = 'test.pdf'
    file_path = os.path.join(os.path.dirname(__file__), file_name)

    file_uploaded = False
    try:
        s3_client.upload_file(file_path, s3_bucket_name, file_name)
        file_uploaded = True
    except:
        print("Error: couldn't upload file")

    assert file_uploaded, "Could not upload file to S3 bucket"

    

@pytest.mark.order(2)
def test_lambda_invoked(logs_client):

    # Wait for a few seconds to make sure the logs are available
    time.sleep(5)

    # Get the latest log stream for the specified log group
    log_streams = logs_client.describe_log_streams(
        logGroupName='/aws/lambda/EncryptPDF',
        orderBy='LastEventTime',
        descending=True,
        limit=1
    )

    latest_log_stream_name = log_streams['logStreams'][0]['logStreamName']

    # Retrieve the log events from the latest log stream
    log_events = logs_client.get_log_events(
        logGroupName='/aws/lambda/EncryptPDF',
        logStreamName=latest_log_stream_name
    )

    success_found = False
    for event in log_events['events']:
        message = json.loads(event['message'])
        status = message.get('record', {}).get('status')
        if status == 'success':
            success_found = True
            break

    assert success_found, "Lambda function execution did not report 'success' status in logs."

@pytest.mark.order(3)
def test_encrypted_file_in_bucket(s3_client):
    # Specify the destination S3 bucket and the expected converted file key
    destination_bucket = 'amzn-s3-demo-bucket-encrypted'
    converted_file_key = 'test_encrypted.pdf'

    try:
        # Attempt to retrieve the metadata of the converted file from the destination S3 bucket
        s3_client.head_object(Bucket=destination_bucket, Key=converted_file_key)
    except s3_client.exceptions.ClientError as e:
        # If the file is not found, the test will fail
        pytest.fail(f"Converted file '{converted_file_key}' not found in the destination bucket: {str(e)}")

def test_cleanup(cleanup):
    # This test uses the cleanup fixture and will be executed last
    pass
```

自動テストスクリプトは、3 つのテスト関数を実行して、アプリの正しいオペレーションを確認します。
+ テスト `test_source_bucket_available` では、テスト PDF ファイルをバケットにアップロードすることで、ソースバケットが正常に作成されたことを確認します。
+ テスト `test_lambda_invoked` は、関数の最新の CloudWatch Logs ログストリームを調べて、テストファイルをアップロードしたときに Lambda 関数が実行され、成功が報告されていることを確認します。
+ テスト `test_encrypted_file_in_bucket` では、レプリケート先バケットに暗号化された `test_encrypted.pdf` ファイルが含まれていることを確認します。

これらのテストがすべて実行されると、スクリプトは追加のクリーンアップステップを実行して、送信元バケットと送信先バケットの両方から `test.pdf` および `test_encrypted.pdf` ファイルを削除します。

AWS SAM テンプレートと同様に、このファイルで指定されたバケット名はプレースホルダーです。テストを実行する前に、このファイルをアプリケーションの実際のバケット名で編集する必要があります。このステップについては、「[自動スクリプトを使用したアプリケーションのテスト](#file-processing-app-test-auto)」で詳しく説明します。

#### テストスクリプト設定ファイル
<a name="file-processing-app-test-config"></a>

次のコードをコピーし、`pytest.ini` という名前のファイルに貼り付けます。

```
[pytest]
markers =
    order: specify test execution order
```

これは、`test_pdf_encrypt.py` スクリプト内のテストを実行する順序を指定するために必要です。

テストを実行するには、次の手順を実行します。

1. `pytest` モジュールがローカル環境にインストールされていることを確認します。`pytest` は以下のコマンドを実行することでインストールできます。

   ```
   pip install pytest
   ```

1. `test.pdf` という名前の PDF ファイルを、`test_pdf_encrypt.py` ファイルと `pytest.ini` ファイルがあるディレクトリに保存します。

1. ターミナルまたはシェルプログラムを開き、テストファイルがあるディレクトリから次のコマンドを実行します。

   ```
   pytest -s -v
   ```

   テストが完了すると、次のようになります。

   ```
   ============================================================== test session starts =========================================================
   platform linux -- Python 3.12.2, pytest-7.2.2, pluggy-1.0.0 -- /usr/bin/python3
   cachedir: .pytest_cache
   hypothesis profile 'default' -> database=DirectoryBasedExampleDatabase('/home/pdf_encrypt_app/.hypothesis/examples')
   Test order randomisation NOT enabled. Enable with --random-order or --random-order-bucket=<bucket_type>
   rootdir: /home/pdf_encrypt_app, configfile: pytest.ini
   plugins: anyio-3.7.1, hypothesis-6.70.0, localserver-0.7.1, random-order-1.1.0
   collected 4 items
   
   test_pdf_encrypt.py::test_source_bucket_available PASSED
   test_pdf_encrypt.py::test_lambda_invoked PASSED
   test_pdf_encrypt.py::test_encrypted_file_in_bucket PASSED
   test_pdf_encrypt.py::test_cleanup PASSED
   Deleted test.pdf from amzn-s3-demo-bucket
   Deleted test_encrypted.pdf from amzn-s3-demo-bucket-encrypted
   
   
   =============================================================== 4 passed in 7.32s ==========================================================
   ```

## 次のステップ
<a name="file-processing-app-next-steps"></a>

これで、サンプルアプリケーションを作成できました。このコードをベースにして、他の種類のファイル処理アプリケーションを作成することができます。`lambda_function.py` ファイル内のコードを変更して、ユースケースのファイル処理ロジックを実装します。

一般的なファイル処理のユースケースの多くには、画像処理が含まれます。Python で画像処理を行う場合、[Pillow](https://pypi.org/project/pillow/) のような一般的な画像処理ライブラリは、通常 C 言語または C\$1\$1 コンポーネントを含んでいます 関数のデプロイパッケージが Lambda 実行環境と互換性があることを確認するには、正しいソースディストリビューションバイナリを使用することが重要です。

AWS SAM を使用してリソースをデプロイする場合、デプロイパッケージに適切なソースディストリビューションを含めるための追加の手順を実行する必要があります。AWS SAM はビルドマシンとは異なるプラットフォームの依存関係をインストールしないため、ビルドマシンが Lambda 実行環境とは異なるオペレーティングシステムまたはアーキテクチャを使用している場合、`requirements.txt` ファイルに正しいソースディストリビューション (`.whl` ファイル) を指定しても機能しません。代わりに、次のいずれかの操作を行います。
+ `sam build` を実行するときは、 `--use-container` オプションを使用します。このオプションを指定すると、AWS SAM は Lambda 実行環境と互換性のあるコンテナベースイメージをダウンロードし、そのイメージを使用して関数のデプロイパッケージを Docker コンテナに構築します。詳細については、「[指定されたコンテナ内における Lambda 関数の構築](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/using-sam-cli-build.html#using-sam-cli-build-options-container)」を参照してください。
+ 正しいソースディストリビューションバイナリを使用して関数の .zip デプロイパッケージを自分で構築し、AWS SAM テンプレートの `CodeUri` として指定したディレクトリに .zip ファイルを保存します。バイナリディストリビューションを使用して Python 用の .zip デプロイパッケージを構築する方法の詳細については、「[依存関係を含めて .zip デプロイパッケージを作成する](python-package.md#python-package-create-dependencies)」および「[ネイティブライブラリとともに .zip デプロイパッケージを作成する](python-package.md#python-package-native-libraries)」を参照してください。

# 定期的にデータベースメンテナンスを実行するアプリケーションを作成する
<a name="scheduled-task-app"></a>

AWS Lambda を使用して、自動システムバックアップ、ファイル変換、メンテナンスタスクなどの定期的なプロセスを置き換えることができます。この例では、古いエントリを削除して DynamoDB テーブルで定期メンテナンスを実行するサーバーレスアプリケーションを作成します。アプリケーションは EventBridge スケジューラを使用して、cron スケジュールで Lambda 関数を呼び出します。呼び出されると、関数は 1 年以上前の項目についてテーブルをクエリし、それらを削除します。関数は、削除された各項目を CloudWatch Logs に記録します。

この例を実装するには、まず DynamoDB テーブルを作成し、関数がクエリするためのテストデータを入力します。次に、EventBridge スケジューラトリガーと IAM 実行ロールを使用して Python Lambda 関数を作成し、関数にテーブルから項目を読み取って削除するアクセス許可を付与します。

![\[\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/ExampleApps/cron_app.png)


**ヒント**  
Lambda を初めて使用する場合は、このサンプルアプリを作成する前にチュートリアル [最初の Lambda 関数を作成する](getting-started.md) を完了することをお勧めします。

AWS マネジメントコンソール を使用してリソースを作成して設定することで、アプリを手動でデプロイできます。AWS Serverless Application Model (AWS SAM) を使用してアプリケーションをデプロイすることもできます。AWS SAM は、Infrastructure as Code (IaC) ツールです。IaC では、リソースを手動で作成するのではなく、コードに定義して自動的にデプロイします。

このサンプルアプリケーションをデプロイする前に、IaC で Lambda を使用する方法の詳細については、「[Lambda と Infrastructure as code (IaC) の使用](foundation-iac.md)」を参照してください。

## 前提条件
<a name="scheduled-task-app-prereqs"></a>

サンプルアプリを作成する前に、必要なコマンドラインツールとインストールされたプログラムがあることを確認してください。
+ **Python**

  アプリケーションをテストするために作成した DynamoDB テーブルにデータを入力するために、この例では Python スクリプトと CSV ファイルを使用してテーブルにデータを書き込みます。Python バージョン 3.8 以降がマシンにインストールされていることを確認してください。
+ **AWS SAM CLI**

  AWS SAM を使用して DynamoDB テーブルを作成し、サンプルアプリをデプロイする場合は、AWS SAM CLI をインストールする必要があります。「*AWS SAM ユーザーガイド*」の「[インストール手順](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html)」に従います。
+ **AWS CLI**

  提供された Python スクリプトを使用してテストテーブルに入力するには、AWS CLI をインストールして設定する必要があります。これは、スクリプトが AWS Identity and Access Management (IAM) 認証情報にアクセスする必要がある AWS SDK for Python (Boto3) を使用するためです。また、AWS SAM を使用してリソースをデプロイする場合も、AWS CLI をインストールする必要があります。「*AWS Command Line Interface ユーザーガイド*」の「[インストール手順](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)」に従って CLI をインストールします。
+ **Docker**

  AWS SAM を使用してアプリケーションをデプロイするには、ビルドマシンに Docker もインストールする必要があります。Docker ドキュメントウェブサイトの「[Docker エンジンのインストール](https://docs.docker.com/engine/install/)」の手順に従います。

## サンプルアプリケーションファイルのダウンロード
<a name="scheduled-task-app-download"></a>

サンプルデータベースと定期メンテナンスアプリを作成するには、プロジェクトディレクトリに以下のファイルを作成する必要があります:

**データベースファイルの例**
+ `template.yaml` - DynamoDB テーブルの作成に使用できる AWS SAM テンプレート
+ `sample_data.csv` - テーブルにロードするサンプルデータを含む CSV ファイル
+ `load_sample_data.py` - CSV ファイル内のデータをテーブルに書き込む Python スクリプト

**定期メンテナンスアプリファイル**
+ `lambda_function.py` - データベースのメンテナンスを実行する Lambda 関数の Python 関数コード
+ `requirements.txt` - Python 関数コードに必要な依存関係を定義するマニフェストファイル
+ `template.yaml` - アプリケーションのデプロイに使用できる AWS SAM テンプレート

**テストファイル**
+ `test_app.py` - テーブルをスキャンし、1 年以上前のすべてのレコードを出力して関数が正常に動作することを確認する Python スクリプト

以下のセクションを展開してコードを表示し、アプリケーションの作成とテストにおける各ファイルの役割の詳細を確認してください。ローカルマシンにファイルを作成するには、以下のコードをコピーして貼り付けます。

### AWS SAM テンプレート (DynamoDB テーブルの例)
<a name="scheduled-task-app-table-yaml"></a>

次のコードをコピーし、`template.yaml` という名前のファイルに貼り付けます。

```
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: SAM Template for DynamoDB Table with Order_number as Partition Key and Date as Sort Key

Resources:
  MyDynamoDBTable:
    Type: AWS::DynamoDB::Table
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Properties:
      TableName: MyOrderTable
      BillingMode: PAY_PER_REQUEST
      AttributeDefinitions:
        - AttributeName: Order_number
          AttributeType: S
        - AttributeName: Date
          AttributeType: S
      KeySchema:
        - AttributeName: Order_number
          KeyType: HASH
        - AttributeName: Date
          KeyType: RANGE
      SSESpecification:
        SSEEnabled: true
      GlobalSecondaryIndexes:
        - IndexName: Date-index
          KeySchema:
            - AttributeName: Date
              KeyType: HASH
          Projection:
            ProjectionType: ALL
      PointInTimeRecoverySpecification:
        PointInTimeRecoveryEnabled: true

Outputs:
  TableName:
    Description: DynamoDB Table Name
    Value: !Ref MyDynamoDBTable
  TableArn:
    Description: DynamoDB Table ARN
    Value: !GetAtt MyDynamoDBTable.Arn
```

**注記**  
AWS SAM テンプレートは、`template.yaml` の標準の命名規則を使用します。この例では、2 つのテンプレートファイルがあります。1 つはサンプルデータベースを作成するもので、もう 1 つはアプリケーション自体を作成するものです。プロジェクトフォルダ内の個別のサブディレクトリに保存します。

この AWS SAM テンプレートは、アプリケーションをテストするために作成する DynamoDB テーブルリソースを定義します。テーブルでは、`Date` のソートキーと一緒に `Order_number` のプライマリキーを使用します。Lambda 関数を日付によって項目を直接検索できるように、`Date-index` という名前の[グローバルセカンダリインデックス](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html)も定義します。

`AWS::DynamoDB::Table` リソースを使用した DynamoDB テーブルの作成と設定の詳細については、「*AWS CloudFormation ユーザーガイド*」の「[AWS::DynamoDB::Table](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dynamodb-table.html)」を参照してください。

### サンプルデータベースデータファイル
<a name="scheduled-task-app-csv-file"></a>

次のコードをコピーし、`sample_data.csv` という名前のファイルに貼り付けます。

```
Date,Order_number,CustomerName,ProductID,Quantity,TotalAmount
2023-09-01,ORD001,Alejandro Rosalez,PROD123,2,199.98
2023-09-01,ORD002,Akua Mansa,PROD456,1,49.99
2023-09-02,ORD003,Ana Carolina Silva,PROD789,3,149.97
2023-09-03,ORD004,Arnav Desai,PROD123,1,99.99
2023-10-01,ORD005,Carlos Salazar,PROD456,2,99.98
2023-10-02,ORD006,Diego Ramirez,PROD789,1,49.99
2023-10-03,ORD007,Efua Owusu,PROD123,4,399.96
2023-10-04,ORD008,John Stiles,PROD456,2,99.98
2023-10-05,ORD009,Jorge Souza,PROD789,3,149.97
2023-10-06,ORD010,Kwaku Mensah,PROD123,1,99.99
2023-11-01,ORD011,Li Juan,PROD456,5,249.95
2023-11-02,ORD012,Marcia Oliveria,PROD789,2,99.98
2023-11-03,ORD013,Maria Garcia,PROD123,3,299.97
2023-11-04,ORD014,Martha Rivera,PROD456,1,49.99
2023-11-05,ORD015,Mary Major,PROD789,4,199.96
2023-12-01,ORD016,Mateo Jackson,PROD123,2,199.99
2023-12-02,ORD017,Nikki Wolf,PROD456,3,149.97
2023-12-03,ORD018,Pat Candella,PROD789,1,49.99
2023-12-04,ORD019,Paulo Santos,PROD123,5,499.95
2023-12-05,ORD020,Richard Roe,PROD456,2,99.98
2024-01-01,ORD021,Saanvi Sarkar,PROD789,3,149.97
2024-01-02,ORD022,Shirley Rodriguez,PROD123,1,99.99
2024-01-03,ORD023,Sofia Martinez,PROD456,4,199.96
2024-01-04,ORD024,Terry Whitlock,PROD789,2,99.98
2024-01-05,ORD025,Wang Xiulan,PROD123,3,299.97
```

このファイルには、DynamoDB テーブルに標準のカンマ区切り (CSV) フォーマットで入力するためのテストデータの例が含まれています。

### サンプルデータをロードする Python スクリプト
<a name="scheduled-task-app-load-script"></a>

次のコードをコピーし、`load_sample_data.py` という名前のファイルに貼り付けます。

```
import boto3
import csv
from decimal import Decimal

# Initialize the DynamoDB client
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('MyOrderTable') 
print("DDB client initialized.")

def load_data_from_csv(filename):
    with open(filename, 'r') as file:
        csv_reader = csv.DictReader(file)
        for row in csv_reader:
            item = {
                'Order_number': row['Order_number'],
                'Date': row['Date'],
                'CustomerName': row['CustomerName'],
                'ProductID': row['ProductID'],
                'Quantity': int(row['Quantity']),
                'TotalAmount': Decimal(str(row['TotalAmount']))
            }
            table.put_item(Item=item)
            print(f"Added item: {item['Order_number']} - {item['Date']}")

if __name__ == "__main__":
    load_data_from_csv('sample_data.csv')
    print("Data loading completed.")
```

この Python スクリプトは、まず AWS SDK for Python (Boto3) を使用して DynamoDB テーブルへの接続を作成します。次に、サンプルデータ CSV ファイル内の各行を繰り返し、その行から項目を作成し、boto3 SDK を使用してその項目を DynamoDB テーブルに書き込みます。

### Python 関数コード
<a name="scheduled-task-app-function-code"></a>

次のコードをコピーし、`lambda_function.py` という名前のファイルに貼り付けます。

```
import boto3
from datetime import datetime, timedelta
from boto3.dynamodb.conditions import Key, Attr
import logging

logger = logging.getLogger()
logger.setLevel("INFO")

def lambda_handler(event, context):
    # Initialize the DynamoDB client
    dynamodb = boto3.resource('dynamodb')
    
    # Specify the table name
    table_name = 'MyOrderTable'
    table = dynamodb.Table(table_name)
    
    # Get today's date
    today = datetime.now()
    
    # Calculate the date one year ago
    one_year_ago = (today - timedelta(days=365)).strftime('%Y-%m-%d')
    
    # Scan the table using a global secondary index
    response = table.scan(
        IndexName='Date-index',
        FilterExpression='#date < :one_year_ago',
        ExpressionAttributeNames={
            '#date': 'Date'
        },
        ExpressionAttributeValues={
            ':one_year_ago': one_year_ago
        }
    )
    
     # Delete old items
    with table.batch_writer() as batch:
        for item in response['Items']:
            Order_number = item['Order_number']
            batch.delete_item(
                Key={
                    'Order_number': Order_number,
                    'Date': item['Date']
                }
            )
            logger.info(f'deleted order number {Order_number}')
    
    # Check if there are more items to scan
    while 'LastEvaluatedKey' in response:
        response = table.scan(
            IndexName='DateIndex',
            FilterExpression='#date < :one_year_ago',
            ExpressionAttributeNames={
                '#date': 'Date'
            },
            ExpressionAttributeValues={
                ':one_year_ago': one_year_ago
            },
            ExclusiveStartKey=response['LastEvaluatedKey']
        )
        
        # Delete old items
        with table.batch_writer() as batch:
            for item in response['Items']:
                batch.delete_item(
                    Key={
                        'Order_number': item['Order_number'],
                        'Date': item['Date']
                    }
                )
    
    return {
        'statusCode': 200,
        'body': 'Cleanup completed successfully'
    }
```

Python 関数コードには、関数が呼び出されたときに Lambda が実行する[ハンドラー関数](python-handler.md) (`lambda_handler`) が含まれています。

EventBridge スケジューラによって関数が呼び出されると、AWS SDK for Python (Boto3) を使用して、定期メンテナンスタスクを実行する DynamoDB テーブルへの接続を作成します。次に、Python `datetime` ライブラリを使用して 1 年前の日付を計算し、これより古い項目についてテーブルをスキャンして削除します。

DynamoDB クエリおよびスキャンオペレーションからの応答は、最大 1 MB のサイズに制限されることに注意してください。レスポンスが 1 MB より大きい場合、DynamoDB はデータをページ分割し、レスポンスに `LastEvaluatedKey` 要素を返します。関数がテーブル内のすべてのレコードを処理するように、このキーがあるかを確認し、テーブル全体がスキャンされるまで、最後に評価された位置からテーブルスキャンを続行します。

### `requirements.txt` マニフェストファイル
<a name="scheduled-task-app-dependencies"></a>

次のコードをコピーし、`requirements.txt` という名前のファイルに貼り付けます。

```
boto3
```

この例では、関数コードには、標準の Python ライブラリに含まれていない依存関係が 1 つだけあります - DynamoDB テーブルから項目をスキャンして削除するために関数が使用する SDK for Python (Boto3)。

**注記**  
SDK for Python (Boto3) のバージョンは Lambda ランタイムの一部として含まれているため、Boto3 を関数のデプロイパッケージに追加せずにコードが実行されます。ただし、関数の依存関係を完全に制御し、バージョン不一致による問題を回避するには、Python のベストプラクティスとして、関数のデプロイパッケージにすべての関数の依存関係を含めることをお勧めします。詳細については、「[Python でのランタイム依存関係](python-package.md#python-package-dependencies)」を参照してください。

### AWS SAM テンプレート (定期メンテナンスアプリケーション)
<a name="scheduled-task-app-table-yaml"></a>

次のコードをコピーし、`template.yaml` という名前のファイルに貼り付けます。

```
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: SAM Template for Lambda function and EventBridge Scheduler rule

Resources:
  MyLambdaFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: ScheduledDBMaintenance
      CodeUri: ./
      Handler: lambda_function.lambda_handler
      Runtime: python3.11
      Architectures:
        - x86_64
      Events:
        ScheduleEvent:
          Type: ScheduleV2
          Properties:
            ScheduleExpression: cron(0 3 1 * ? *)
            Description: Run on the first day of every month at 03:00 AM
      Policies:
        - CloudWatchLogsFullAccess
        - Statement:
            - Effect: Allow
              Action:
                - dynamodb:Scan
                - dynamodb:BatchWriteItem
              Resource: !Sub 'arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/MyOrderTable'

  LambdaLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub /aws/lambda/${MyLambdaFunction}
      RetentionInDays: 30

Outputs:
  LambdaFunctionName:
    Description: Lambda Function Name
    Value: !Ref MyLambdaFunction
  LambdaFunctionArn:
    Description: Lambda Function ARN
    Value: !GetAtt MyLambdaFunction.Arn
```

**注記**  
AWS SAM テンプレートは、`template.yaml` の標準の命名規則を使用します。この例では、2 つのテンプレートファイルがあります。1 つはサンプルデータベースを作成するもので、もう 1 つはアプリケーション自体を作成するものです。プロジェクトフォルダ内の個別のサブディレクトリに保存します。

この AWS SAM テンプレートは、アプリケーションのリソースを定義すします。`AWS::Serverless::Function` リソースを使用して Lambda 関数を定義します。EventBridge スケジューラのスケジュールと Lambda 関数を呼び出すトリガーは、`ScheduleV2` のタイプを使用しているこのリソースの `Events` プロパティを使用して作成されます。AWS SAM テンプレートでの EventBridge スケジューラのスケジュールの定義の詳細については、「*AWS Serverless Application Model デベロッパーガイド*」の「[ScheduleV2](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-schedulev2.html)」を参照してください。

Lambda 関数と EventBridge スケジューラのスケジュールに加えて、削除された項目のレコードを送信する関数の CloudWatch ロググループも定義します。

### テストスクリプト
<a name="scheduled-task-app-test-script"></a>

次のコードをコピーし、`test_app.py` という名前のファイルに貼り付けます。

```
import boto3
from datetime import datetime, timedelta
import json

# Initialize the DynamoDB client
dynamodb = boto3.resource('dynamodb')

# Specify your table name
table_name = 'YourTableName'
table = dynamodb.Table(table_name)

# Get the current date
current_date = datetime.now()

# Calculate the date one year ago
one_year_ago = current_date - timedelta(days=365)

# Convert the date to string format (assuming the date in DynamoDB is stored as a string)
one_year_ago_str = one_year_ago.strftime('%Y-%m-%d')

# Scan the table
response = table.scan(
    FilterExpression='#date < :one_year_ago',
    ExpressionAttributeNames={
        '#date': 'Date'
    },
    ExpressionAttributeValues={
        ':one_year_ago': one_year_ago_str
    }
)

# Process the results
old_records = response['Items']

# Continue scanning if we have more items (pagination)
while 'LastEvaluatedKey' in response:
    response = table.scan(
        FilterExpression='#date < :one_year_ago',
        ExpressionAttributeNames={
            '#date': 'Date'
        },
        ExpressionAttributeValues={
            ':one_year_ago': one_year_ago_str
        },
        ExclusiveStartKey=response['LastEvaluatedKey']
    )
    old_records.extend(response['Items'])

for record in old_records:
    print(json.dumps(record))

# The total number of old records should be zero.
print(f"Total number of old records: {len(old_records)}")
```

このテストスクリプトは、AWS SDK for Python (Boto3) を使用して DynamoDB テーブルへの接続を作成し、1 年以上前の項目をスキャンします。Lambda 関数が正常に実行されたかどうかを確認するには、テストの最後に、関数はテーブルに残っている 1 年以上前のレコードの数を出力します。Lambda 関数が成功した場合、テーブル内の古いレコードの数はゼロになっているはずです。

## DynamoDB のサンプルテーブルの作成と入力
<a name="scheduled-task-app-create-table"></a>

定期メンテナンスアプリケーションをテストするには、まず DynamoDB テーブルを作成し、いくつかのサンプルデータを入力します。テーブルは、AWS マネジメントコンソール を使用して手動で作成することも、AWS SAM を使用して作成することもできます。AWS SAM を使用して、いくつかの AWS CLI コマンドでテーブルをすばやく作成および設定することをお勧めします。

------
#### [ Console ]

**DynamoDB テーブルを作成する**

1. DynamoDB コンソールで [[テーブル]](https://console.aws.amazon.com/dynamodbv2/home#tables) ページを開きます。

1. **[テーブルの作成]** を選択します。

1. 以下の操作でテーブルを作成します:

   1. **[テーブルの詳細]** の **[テーブル名]** に **MyOrderTable** を入力します。

   1. **[パーティションキー]** に **Order\$1number** と入力し、型を **[文字列]** のままにします。

   1. **[ソートキー]** に、**Date** と入力し、型を **[文字列]** のままにします。

   1. **[テーブル設定]** を **[デフォルト設定]** に設定したままにして、**[テーブルの作成]** を選択します。

1. テーブルの作成が完了し、その **[ステータス]** が **[アクティブ]** と表示されたら、以下を実行してグローバルセカンダリインデックス (GSI) を作成します。アプリケーションは、この GSI を使用して日付で項目を直接検索し、削除する項目を決定します。

   1. テーブルのリストから **[MyOrderTable]** を選択します。

   1. **[インデックス]** タブを選択します。

   1. **[グローバルセカンダリインデックス]** で、**[インデックスの作成]** を選択します。

   1. **[インデックスの詳細]** で、**[パーティションキー]**に **Date** を入力し、**[データ型]** を **[文字列]** に設定したままにします。

   1. **[Index name]** (インデックス名) に **Date-index** と入力します。

   1. 他のすべてのパラメータをデフォルト値に設定したまま、ページの下部までスクロールし、**[インデックスの作成]** を選択します。

------
#### [ AWS SAM ]

**DynamoDB テーブルを作成する**

1. DynamoDB テーブルの `template.yaml` ファイルを保存したフォルダに移動します。この例では 2 つの `template.yaml` ファイルを使用することに注意してください。それらが別々のサブフォルダに保存され、DynamoDB テーブルを作成するためのテンプレートを含む正しいフォルダに格納されていることを確認します。

1. 以下のコマンドを実行してください。

   ```
   sam build
   ```

   このコマンドによって、デプロイするリソースのビルドアーティファクトが収集され、それらをデプロイする適切な形式と場所に配置します。

1. `template.yaml` ファイルで指定された DynamoDB リソースを作成するには、以下のコマンドを実行します。

   ```
   sam deploy --guided
   ```

   `--guided` フラグを使用すると、AWS SAM にデプロイプロセスの手順が示されます。このデプロイでは、**cron-app-test-db** の `Stack name` を入力し、Enter を使用して他のすべてのオプションのデフォルトを受け入れます。

   AWS SAM が DynamoDB リソースの作成を完了すると、以下のメッセージが表示されます。

   ```
   Successfully created/updated stack - cron-app-test-db in us-west-2
   ```

1. さらに、DynamoDB コンソールの[テーブル](https://console.aws.amazon.com/dynamodbv2/home#tables)ページを開くことで、DynamoDB テーブルが作成されたことを確認できます。`MyOrderTable` という名前のテーブルが表示されます。

------

テーブルを作成したら、次にサンプルデータを追加してアプリケーションをテストします。先ほどダウンロードした CSV ファイル `sample_data.csv` には、注文番号、日付、顧客および注文情報で構成される多数のサンプルエントリが含まれています。このデータをテーブルに追加するには、提供された Python スクリプト `load_sample_data.py` を使用します。

**サンプルデータをテーブルに追加するには**

1. `sample_data.csv` と `load_sample_data.py` ファイルが含まれているディレクトリに移動します。これらのファイルが別のディレクトリにある場合は、同じ場所に保存されるようにファイルを移動します。

1. Python の仮想環境を作成してスクリプトを実行するには、以下のコマンドを実行します。以下のステップでは AWS SDK for Python (Boto3) をインストールする必要があるため、仮想環境を使用することをお勧めします。

   ```
   python -m venv venv
   ```

1. 以下のコマンドを実行して、仮想環境を有効にします。

   ```
   source venv/bin/activate
   ```

1. 以下のコマンドを実行して、SDK for Python (Boto3) を仮想環境にインストールします。スクリプトは、このライブラリを使用して DynamoDB テーブルに接続し、項目を追加します。

   ```
   pip install boto3
   ```

1. 以下のコマンドの実行によってスクリプトを実行し、テーブルに入力します。

   ```
   python load_sample_data.py
   ```

   スクリプトが正常に実行される場合は、ロードして `Data loading completed` を報告するときに、各項目をコンソールに出力する必要があります。

1. 以下のコマンドを実行して、仮想環境を無効にします。

   ```
   deactivate
   ```

1. データを DynamoDB テーブルにロードしたことを確認するには、以下の手順を実行します。

   1. DynamoDB コンソールの [[項目を探す]](https://console.aws.amazon.com/dynamodbv2/home#item-explorer) ページを開いて、テーブル (`MyOrderTable`) を選択します。

   1. **[返された項目]** ペインには、スクリプトがテーブルに追加した CSV ファイルから 25 個の項目が表示されているはずです。

## 定期メンテナンスアプリケーションの作成
<a name="scheduled-task-app-create-app"></a>

このサンプルアプリケーションのリソースは、AWS マネジメントコンソール または AWS SAM を使用して着実に作成およびデプロイできます。本番環境では、手動プロセスを使用せずにサーバーレスアプリケーション繰り返しデプロイするために、AWS SAM のような Infrustracture-as-Code (IaC) ツールを使用することをお勧めします。

この例では、コンソールの指示に従って各 AWS リソースを個別に設定する方法を学習するか、AWS SAM の指示に従って、AWS CLI のコマンドを使用してアプリをすばやくデプロイします。

------
#### [ Console ]

**AWS マネジメントコンソール を使用して関数を作成するには**

まず、基本的なスターターコードを含む関数を作成します。次に、Lambda コードエディタでコードを直接コピーして貼り付けるか、コードを `.zip` パッケージとしてアップロードして、このコードを独自の関数コードに置き換えます。このタスクでは、コードをただコピーして貼り付けることをお勧めします。

1. Lambda コンソールの [[関数]](https://console.aws.amazon.com/lambda/home#/functions) ページを開きます。

1. **関数の作成** を選択します。

1. **Author from scratch** を選択します。

1. **基本的な情報** で、以下の作業を行います。

   1. **[関数名]** に「`ScheduledDBMaintenance`」と入力します。

   1. **[ランタイム]** では、最新の Python バージョンを選択します。

   1. **[アーキテクチャ]** で **[x86\$164]** を選択します。

1. [**関数の作成**] を選択してください。

1. 関数を作成したら、指定された関数コードを使用して関数を設定できます。

   1. **[コードソース]** ペインで、Lambda が作成した Hello world コードを、前に保存した `lambda_function.py` ファイルの Python 関数コードに置き換えます。

   1. **[DEPLOY]** セクションで、**[デプロイ]** を選択して関数のコードを更新します。  
![\[\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/getting-started-tutorial/deploy-console.png)

**関数のメモリとタイムアウトを設定するには (コンソール）**

1. 関数の **[設定]** タブを選択します。

1. **[一般設定]** ペインで、**[編集]** を選択します。

1. **[メモリ]** を 256 MB に設定し、**[タイムアウト]**を 15 秒に設定します。例えば本番環境のように、多数のレコードを含む大きなテーブルを処理する場合は、**[タイムアウト]**をより大きな数に設定することを検討してください。これにより、関数がデータベースをスキャンしてクリーンにするための時間が長くなります。

1. **[保存]** を選択します。

**ログ形式を設定するには (コンソール）**

Lambda 関数を設定して、非構造化テキスト形式または JSON 形式でログを出力できます。ログデータの検索とフィルタリングを容易にするために、ログには JSON 形式を使用することをお勧めします。Lambda ログ設定オプションの詳細については、「[Lambda 関数の高度なログ記録コントロールの設定](monitoring-logs.md#monitoring-cloudwatchlogs-advanced)」を参照してください。

1. 関数の **[設定]** タブを選択します。

1. **[モニタリングおよび運用ツール]** を選択します。

1. **[ログ記録設定]** ペインで、**[編集]** を選択します。

1. **[ログ記録設定]** で、**[JSON]**を選択します。

1. **[保存]** を選択します。

**IAM 許可をセットアップするには**

関数に DynamoDB 項目の読み取りと削除に必要なアクセス許可を付与するには、必要なアクセス許可を定義するポリシーを関数の[実行ロール](lambda-intro-execution-role.md)に追加する必要があります。

1. **[設定]** タブを開き、左側のナビゲーションバーから **[アクセス許可]** を選択します。

1. **[実行ロール]** の下にあるロール名を選択します。

1. IAM コンソールで、**[アクセス許可を追加]** を選択し、次いで **[インラインポリシーを作成]** を選択します。

1. JSON エディタを使用して、以下のポリシーを入力します:  
****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "dynamodb:Scan",
                   "dynamodb:DeleteItem",
                   "dynamodb:BatchWriteItem"
               ],
               "Resource": "arn:aws:dynamodb:*:*:table/MyOrderTable"
           }
       ]
   }
   ```

1. ポリシー **DynamoDBCleanupPolicy** に名前を付け、作成します。

**EventBridge スケジューラをトリガーとして設定するには (コンソール)**

1. [[EventBridge コンソール](https://console.aws.amazon.com/events/home)] を開きます。

1. 左側のナビゲーションペインで、**[スケジューラ]** セクションの下の **[スケジューラ]** を選択します。

1. **[スケジュールを作成]** を選択します。

1. 以下を実行してスケジュールを設定します:

   1. **[スケジュール名]** の下で、スケジュールの名前を入力します (例えば、**DynamoDBCleanupSchedule**)。

   1. **[スケジュールパターン]** の下で **[定期的なスケジュール]** を選択します。

   1. **[スケジュールタイプ]** では、デフォルトを **[Cron ベースのスケジュール]** のままにし、以下のスケジュールの詳細を入力します:
      + **[分]**: **0**
      + **[時間]**: **3**
      + **[月日]**: **1**
      + **[月]**: **\$1**
      + **[曜日]**: **?**
      + **[年]**: **\$1**

      この cron 式は評価されると、毎月 1 日午前 3 時に実行されます。

   1. **[フレキシブルタイムウィンドウ]** で **[オフ]** を選択します。

1. [**次へ**] を選択します。

1. 以下を実行して Lambda 関数のトリガーを設定します:

   1. **[ターゲットの詳細]** ペインで、**[ターゲット API]** を **[テンプレート化されたターゲット]** に設定したまま、**[AWS Lambda の呼び出し]** を選択します。

   1. **[呼び出す]** で、ドロップダウンリストから [Lambda 関数 (`ScheduledDBMaintenance`)] を選択します。

   1. **[ペイロード]** を空のままにして、**[次へ]** を選択します。

   1. **[アクセス許可]** までスクロールダウンし、**[このスケジュールの新しいロールを作成する]** を選択します。コンソールを使用して新しい EventBridge スケジューラのスケジュールを作成すると、EventBridge スケジューラは、スケジュールが関数を呼び出すために必要なアクセス許可を持つ新しいポリシーを作成します。スケジュール許可の管理の詳細については、「*EventBridge スケジューラユーザーガイド*」の「[Cron ベースのスケジュール](https://docs.aws.amazon.com/scheduler/latest/UserGuide/schedule-types.html#cron-based)」を参照してください。

   1. [**次へ**] を選択します。

1. 設定を確認し、**[スケジュールを作成]** を選択してスケジュールと Lambda トリガーの作成を完了します。

------
#### [ AWS SAM ]

**AWS SAM を使用してアプリケーションをデプロイするには**

1. アプリケーションの `template.yaml` ファイルを保存したフォルダに移動します。この例では 2 つの `template.yaml` ファイルを使用することに注意してください。これらは別々のサブフォルダに保存され、アプリケーションを作成するためのテンプレートを含む正しいフォルダに保存されていることを確認します。

1. 以前にダウンロードした `lambda_function.py` および `requirements.txt` ファイルを同じフォルダにコピーします。AWS SAM テンプレートで指定されたコードの場所は `./` です。つまり、現在の場所です。アプリのデプロイを試みると、AWS SAM はこのフォルダで Lambda 関数コードを検索します。

1. 以下のコマンドを実行してください。

   ```
   sam build --use-container
   ```

   このコマンドによって、デプロイするリソースのビルドアーティファクトが収集され、それらをデプロイする適切な形式と場所に配置します。`--use-container` オプションを指定すると、Lambda のような Docker コンテナ内に関数がビルドされます。ここではこれを使用するため、ビルドを実行するためにローカルマシンに Python 3.12 をインストールする必要はありません。

1. `template.yaml` ファイルで指定された Lambda および EventBridge スケジューラリソースを作成するには、以下のコマンドを実行します。

   ```
   sam deploy --guided
   ```

   `--guided` フラグを使用すると、AWS SAM にデプロイプロセスの手順が示されます。このデプロイでは、**cron-maintenance-app** の `Stack name` を入力し、Enter を使用して他のすべてのオプションのデフォルトを受け入れます。

   AWS SAM が Lambda および EventBridge スケジューラリソースの作成を完了すると、以下のメッセージが表示されるはずです。

   ```
   Successfully created/updated stack - cron-maintenance-app in us-west-2
   ```

1. さらに、Lambda コンソールの [[関数]](https://console.aws.amazon.com/lambda/home#/functions) ページを開くことで、Lambda 関数が作成されたことを確認できます。`ScheduledDBMaintenance` という名前の関数が表示されるはずです。

------

## アプリのテスト
<a name="scheduled-task-app-test-app"></a>

 スケジュールが関数を正しくトリガーし、関数がデータベースからレコードを正しくクリーンアップすることをテストするには、スケジュールを一時的に変更して、特定の時間に 1 回実行するようにします。その後、`sam deploy` を再度実行して、毎月 1 回実行するように繰り返しスケジュールをリセットできます。

**AWS マネジメントコンソール を使用してアプリケーションを実行するには**

1. EventBridge スケジューラコンソールページに戻ります。

1. スケジュールを選択してから、**[編集]** を選択します。

1. **[スケジュールパターン]** セクションの **[繰り返し]** の下にある **[1 回限りのスケジュール]** を選択します。

1.  呼び出し時間を数分後に設定し、設定を確認してから **[保存]** を選択します。

 スケジュールが実行され、ターゲットが呼び出されたら、`test_app.py` スクリプトを実行して、関数が DynamoDB テーブルから古いレコードをすべて正常に削除したことを確認します。

**古いレコードが Python スクリプトを使用して削除されていることを確認するには**

1.  コマンドラインで、`test_app.py` を保存したフォルダに移動します。

1. スクリプトを実行します。

   ```
   python test_app.py
   ```

    成功すると、以下の出力が表示されます。

   ```
   Total number of old records: 0
   ```

## 次のステップ
<a name="scheduled-task-app-next-steps"></a>

 特定のアプリケーション要件を満たすために、EventBridge スケジューラのスケジュールを変更できるようになりました。EventBridge スケジューラは、以下のスケジュール式をサポートしています: cron、レート、1 回限りのスケジュール。

 EventBridge スケジューラのスケジュール式に関する詳細については、「*EventBridge スケジューラユーザーガイド*」の「[スケジュールタイプ](https://docs.aws.amazon.com/scheduler/latest/UserGuide/schedule-types.html)」を参照してください。*IAM ユーザーガイド*の[アクセス管理](https://docs.aws.amazon.com/IAM/latest/UserGuide/access.html) 

# Lambda 耐久関数を使用した注文処理システムの作成
<a name="order-processing-app"></a>

**注記**  
NEED: API Gateway、Durable Function ワークフロー、サポートサービス (DynamoDB、EventBridge) を示すアーキテクチャ図を追加する

## 前提条件
<a name="order-processing-prerequisites"></a>
+ AWS CLIインストールおよび設定済みの 
+ NEED: 特定の Durable Functions の要件

## ソースコードファイルを作成する
<a name="order-processing-source"></a>

プロジェクトディレクトリに次のファイルを作成します。
+ `lambda_function.py` – 関数コード
+ `requirements.txt` – 依存関係マニフェスト

### 関数コード
<a name="order-processing-function-code"></a>

```
# NEED: Verify correct imports
import boto3
import json

def lambda_handler(event, context):
    # NEED: Verify DurableContext syntax
    durable = context.durable
    
    try:
        # Validate and store order
        order = await durable.step('validate', async () => {
            return validate_order(event['order'])
        })
        
        # Process payment
        # NEED: Verify wait syntax
        await durable.wait(/* wait configuration */)
        
        # Additional steps
        # NEED: Complete implementation
        
    except Exception as e:
        # NEED: Error handling patterns
        raise e

def validate_order(order_data):
    # NEED: Implementation
    pass
```

### 要件ファイル
<a name="order-processing-requirements"></a>

```
# NEED: List of required packages
```

## アプリケーションのデプロイ
<a name="order-processing-deploy"></a>

### 注文用の DynamoDB テーブルを作成する
<a name="order-processing-dynamodb"></a>

1. DynamoDB コンソール ([https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)) を開きます。

1. [**Create table (テーブルの作成)**] を選択します。

1. **[テーブル名]** に「**Orders**」と入力します。

1. **[パーティションキー]** に「**orderId**」と入力します。

1. 他の設定はすべてデフォルトのままにする

1. [**Create table (テーブルの作成)**] を選択します。

### Lambda 関数を作成する
<a name="order-processing-lambda"></a>

1. Lambda コンソール ([https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda/)) を開く

1. **[Create function]** (関数の作成) を選択します。

1. **[一から作成]** を選択します。

1. **[関数名]** に **ProcessOrder** と入力します。

1. **[ランタイム]** では、任意のランタイムを選択します。

1. NEED: Durable Functions 固有の設定を追加する

1. **[Create function]** (関数の作成) を選択します。

### API ゲートウェイエンドポイントを作成する
<a name="order-processing-apigateway"></a>

1. API ゲートウェイコンソール ([https://console.aws.amazon.com/apigateway/](https://console.aws.amazon.com/apigateway/)) を開く

1. **[API を作成]** を選択する

1. **[HTTP API]** を選択する

1. **[ビルド]** を選択する

1. Lambda 関数との統合を追加する

1. 注文処理のルートを設定する

1. API をデプロイする

## アプリのテスト
<a name="order-processing-test"></a>

テストオーダーを送信する:

```
{
    "orderId": "12345",
    "items": [
        {
            "productId": "ABC123",
            "quantity": 1
        }
    ]
}
```

NEED: Durable Functions に特定のモニタリング手順を追加する

## 次のステップ
<a name="order-processing-next-steps"></a>

### ビジネスロジックを追加する
<a name="order-processing-business-logic"></a>

インベントリ管理を実装する:

```
async def check_inventory(order):
    # Add inventory check logic
    pass
```

料金計算を追加する:

```
async def calculate_total(order):
    # Add pricing logic
    pass
```

### エラー処理を改善する
<a name="order-processing-error-handling"></a>

補償ロジックを追加する:

```
async def reverse_payment(order):
    # Add payment reversal logic
    pass
```

注文のキャンセルを処理する:

```
async def cancel_order(order):
    # Add cancellation logic
    pass
```

### 外部システムを統合する
<a name="order-processing-integrations"></a>

```
async def notify_shipping_provider(order):
    # Add shipping integration
    pass

async def send_customer_notification(order):
    # Add notification logic
    pass
```

### モニタリングを拡張する
<a name="order-processing-monitoring"></a>
+ CloudWatch ダッシュボードを作成する
+ 注文処理時間のメトリクスを設定する
+ 遅延注文のアラートを設定する