
Powertools for AWS Lambda (Python) の Parameters を使うと AWS Systems Manager Parameter Store / AWS Secrets Manager / AWS AppConfig / Amazon DynamoDB から AWS Lambda 関数で使うパラメータ(何かしらの値)を簡単に取得できる❗️また取得したパラメータを内部的にキャッシュして,パラメータの過剰な取得を抑制する仕組みもある.個人的には AWS Systems Manager Parameter Store をバックエンドによく使っている👌
Amazon DynamoDB からパラメータを取得する場合は Powertools for AWS Lambda (Python) の DynamoDBProvider を使う.しかし DynamoDBProvider は現状 Amazon DynamoDB テーブルからしかパラメータを取得できず,データ構造的に Amazon DynamoDB テーブルの GSI (Global Secondary Index) からパラメータを取得したいという場面があったりする.今回は「カスタムプロバイダ」を実装して GSI からパラメータを取得してみた \( 'ω')/
1. Amazon DynamoDB テーブルからパラメータを取得する
まずは Amazon DynamoDB テーブルからパラメータを取得する.今回は複数値を取得する get_multiple() を前提にする.
👾 template.yaml(一部)
Amazon DynamoDB テーブルは Powertools ドキュメントの例を参考に AWS SAM (AWS CloudFormation) で以下のように構築した.パーティションキーは id で,ソートキーは sk となる.
Resources: Table: Type: AWS::DynamoDB::Table Properties: TableName: parameters AttributeDefinitions: - AttributeName: id AttributeType: S - AttributeName: sk AttributeType: S KeySchema: - AttributeName: id KeyType: HASH - AttributeName: sk KeyType: RANGE BillingMode: PAY_PER_REQUEST
そして,同じく Powertools ドキュメントに載っているサンプルデータを AWS CLI で登録しておく.
$ aws dynamodb put-item --table-name parameters \ --item '{ "id": { "S": "config" }, "sk": { "S": "endpoint_comments" }, "value": { "S": "https://jsonplaceholder.typicode.com/comments/" } }' $ aws dynamodb put-item --table-name parameters \ --item '{ "id": { "S": "config" }, "sk": { "S": "limit" }, "value": { "S": "10" } }'
最終的に以下のようになる👌
| id | sk | value |
|---|---|---|
| config | endpoint_comments | https://jsonplaceholder.typicode.com/comments/ |
| config | limit | 10 |
👾 app.py
AWS Lambda 関数は簡単に実装できる❗️Amazon DynamoDB テーブル parameters を参照するように DynamoDBProvider を初期化して,get_multiple() を使って config という値をキーにパラメータを取得している.デフォルトではパラメータを 5秒間 キャッシュするけど,今回は動作確認も兼ねて max_age を設定して 30秒間 にした.
from aws_lambda_powertools.utilities import parameters dynamodb_provider = parameters.DynamoDBProvider(table_name='parameters') def lambda_handler(event, context): configs = dynamodb_provider.get_multiple('config', max_age=30) print(configs)
動作確認
AWS Lambda 関数を定期的に実行しつつ,途中で以下のコマンドを実行して3つ目の config を追加する.値は適当💨
$ aws dynamodb put-item --table-name parameters \ --item '{ "id": { "S": "config" }, "sk": { "S": "sort" }, "value": { "S": "ASC" } }'
結果的にプロパティのキャッシュが切れてから3つ目の config も取得された👌
{'endpoint_comments': 'https://jsonplaceholder.typicode.com/comments/', 'limit': '10'}
{'endpoint_comments': 'https://jsonplaceholder.typicode.com/comments/', 'limit': '10'}
{'endpoint_comments': 'https://jsonplaceholder.typicode.com/comments/', 'limit': '10'}
{'endpoint_comments': 'https://jsonplaceholder.typicode.com/comments/', 'limit': '10', 'sort': 'ASC'}
2. Amazon DynamoDB GSI (Global Secondary Index) パラメータを取得する
今度は Amazon DynamoDB GSI (Global Secondary Index) からパラメータを取得する.しかし Powertools for AWS Lambda (Python) の DynamoDBProvider は GSI をサポートしていないためカスタムプロバイダを実装する.同じく今回は複数値を取得する get_multiple() を前提にする.GSI サポートは issue にもなかった💨(特に需要なさそう?)
👾 template.yaml(一部)
Amazon DynamoDB テーブルは少し構造を変えて uuid をパーティションキーにした.そして,id-index GSI では id をパーティションキーにして,最初の例と同じデータを取得できるようにした.
Resources: Table: Type: AWS::DynamoDB::Table Properties: TableName: parameters AttributeDefinitions: - AttributeName: uuid AttributeType: S - AttributeName: id AttributeType: S KeySchema: - AttributeName: uuid KeyType: HASH BillingMode: PAY_PER_REQUEST GlobalSecondaryIndexes: - IndexName: id-index KeySchema: - AttributeName: id KeyType: HASH Projection: ProjectionType: ALL
同じようにサンプルデータを AWS CLI で登録しておく.
$ aws dynamodb put-item --table-name parameters \ --item '{ "uuid": { "S": "d33b9dca-952c-4218-b05e-cbd2222ef766" }, "id": { "S": "config" }, "sk": { "S": "endpoint_comments" }, "value": { "S": "https://jsonplaceholder.typicode.com/comments/" } }' $ aws dynamodb put-item --table-name parameters \ --item '{ "uuid": { "S": "c2be3412-1107-48d0-b992-750b8fcd4d42" }, "id": { "S": "config" }, "sk": { "S": "limit" }, "value": { "S": "10" } }'
最終的に以下のようになる👌
| uuid | id | sk | value |
|---|---|---|---|
| d33b9dca-952c-4218-b05e-cbd2222ef766 | config | endpoint_comments | https://jsonplaceholder.typicode.com/comments/ |
| c2be3412-1107-48d0-b992-750b8fcd4d42 | config | limit | 10 |
👾 dynamodb.py
次にカスタムプロバイダ DynamoDBIndexProvider を実装する.サンプルとして実装量をできる限り減らしているけど,汎用的に実装するのであれば DynamoDBProvider の実装を参考にして,指定できる値を増やしたり,LastEvaluatedKey を評価したりすると良いと思う👀
カスタムプロバイダの実装方法は Powertools ドキュメントにも載っているけど,BaseProvider を継承して _get() と _get_multiple() を実装すれば OK👌今回は複数値を前提にしているため,_get() は NotImplementedError を返して,_get_multiple() では GSI に Query を実行している.
import boto3 from aws_lambda_powertools.utilities.parameters import BaseProvider class DynamoDBIndexProvider(BaseProvider): def __init__(self, table_name, index_name): self.index_name = index_name self.table = boto3.resource('dynamodb').Table(table_name) super().__init__() def _get(self): raise NotImplementedError def _get_multiple(self, id): response = self.table.query( IndexName=self.index_name, KeyConditionExpression='id = :id', ExpressionAttributeValues={':id': id}, ) return {item['sk']: item['value'] for item in response['Items']}
👾 app.py
こっちはほぼ同じで,Powertools for AWS Lambda (Python) の DynamoDBProvider を DynamoDBIndexProvider に置き換えた程度👌 GSI 名を index_name で指定している〜
from dynamodb import DynamoDBIndexProvider dynamodb_provider = DynamoDBIndexProvider(table_name='parameters', index_name='id-index') def lambda_handler(event, context): configs = dynamodb_provider.get_multiple('config', max_age=30) print(configs)
動作確認
同じく AWS Lambda 関数を定期的に実行しつつ,途中で3つ目の config を追加する.
$ aws dynamodb put-item --table-name parameters \ --item '{ "uuid": { "S": "571a981c-9002-4e2f-b3e5-207f8a0ce1fd" }, "id": { "S": "config" }, "sk": { "S": "sort" }, "value": { "S": "ASC" } }'
結果的にプロパティのキャッシュが切れてから3つ目の config も取得された👌
{'limit': '10', 'endpoint_comments': 'https://jsonplaceholder.typicode.com/comments/'}
{'limit': '10', 'endpoint_comments': 'https://jsonplaceholder.typicode.com/comments/'}
{'limit': '10', 'endpoint_comments': 'https://jsonplaceholder.typicode.com/comments/'}
{'limit': '10', 'endpoint_comments': 'https://jsonplaceholder.typicode.com/comments/', 'sort': 'ASC'}
まとめ
Powertools for AWS Lambda (Python) の Parameters で Amazon DynamoDB テーブルの GSI (Global Secondary Index) からパラメータを取得する場合はカスタムプロバイダを実装しよう❗️