![](https://cdn-ak.f.st-hatena.com/images/fotolife/k/kakku22/20240713/20240713191732.png)
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 をバックエンドによく使っている👌
docs.powertools.aws.dev
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
を評価したりすると良いと思う👀
github.com
カスタムプロバイダの実装方法は 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) からパラメータを取得する場合はカスタムプロバイダを実装しよう❗️