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') deflambda_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 classDynamoDBIndexProvider(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): raiseNotImplementedErrordef_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') deflambda_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)からパラメータを取得する場合はカスタムプロバイダを実装しよう❗️