DynamoDB StreamsのREMOVEイベントとTTL(Time to Live)でハマった話
こんにちは。 OSS大好きなshoitoです。
最近、DynamoDB Streamsを利用して実装していた機能で、ちょっとハマったことがあったので紹介します。 ユーザーの操作によるDynamoDBテーブルのレコードの削除に伴うREMOVEイベントは考慮していたけど、TTL(Time to Live)によるレコードの削除に伴うREMOVEイベントの考慮が漏れてしまっていた、という内容です。
以下の公式ガイドに気付いてれば良かったです...。
DynamoDB ストリーム および Time To Live https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/time-to-live-ttl-streams.html
DynamoDB StreamsとTTL(Time to Live)
DynamoDB Streamsは、DynamoDBテーブルのストリームの管理から有効化しておくと、レコードの追加、変更、削除のイベントをほぼリアルタイムに受けられるようになります。
DynamoDB ストリーム を使用したテーブルアクティビティのキャプチャ https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Streams.html
DynamoDB Streamsのイベントとしては、以下の3つが定義されています。 https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/APIReference/API_streams_Record.html
- INSERT: レコードが追加された
- MODIFY: レコードの属性が変更された
- REMOVE: レコードが削除された
TTLは、以下のブログでも紹介されているように、指定した期間経過後にレコードを自動で削除する機能です。
やりたかったこととハマったこと
DynamoDB Streamsを利用して実装していた機能なのですが、ユーザー操作により、DynamoDBテーブルのレコードが削除された際に、それをトリガーにLambdaを実行するものでした。
機能実装を終えた気になっていたんですが、開発環境にデプロイしてから数日経過後に 「TTLで消えたレコードのイベントも処理されてません?」 とチームメンバーに訊かれて、TTL設定されてたのか、おやおやとなりました。
DynamoDBテーブルからレコードが消された場合は REMOVE
イベントが流れるので、ユーザーによる操作ではなくTTLでレコードが消された場合も同様です。
今回は ユーザー操作により、DynamoDBテーブルのレコードが削除された際に
という条件だったので、TTLのケースは除外する必要がありました。
Lambdaが受け取るイベントのJSONを見ると、TTLでレコードが削除された時とそれ以外で削除された時では、内容が一部違いました。
ユーザー操作によりレコードが削除されたときのLambdaが受け取るJSON
{ 'Records':[ { 'eventID':'7e3a89f72e3ea8c077aa5fa4de5661da', 'eventName':'REMOVE', 'eventVersion':'1.1', 'eventSource':'aws:dynamodb', 'awsRegion':'ap-northeast-1', 'dynamodb':{ 'ApproximateCreationDateTime':1558672104.0, 'Keys':{ .... }, 'OldImage':{ .... }, 'SequenceNumber':'69657600000000044131896862', 'SizeBytes':300, 'StreamViewType':'NEW_AND_OLD_IMAGES' }, 'eventSourceARN':'....' } ] }
よく見ないと分からないのですが、TTLでレコードが削除された時は以下のように userIdentity
が含まれている点が違います。
{ 'Records':[ { 'eventID':'8558e9b1387c639f1ac3e73a8ced5a00', 'eventName':'REMOVE', 'eventVersion':'1.1', 'eventSource':'aws:dynamodb', 'awsRegion':'ap-northeast-1', 'dynamodb':{ 'ApproximateCreationDateTime':1559538087.0, 'Keys':{ .... }, 'OldImage':{ .... }, 'SequenceNumber':'116861500000000027471850174', 'SizeBytes':330, 'StreamViewType':'NEW_AND_OLD_IMAGES' }, 'userIdentity':{ 'principalId':'dynamodb.amazonaws.com', 'type':'Service' }, 'eventSourceARN':'...' } ] }
確かに、公式ガイドに記載されている通りですが、後で気付きました。 https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/time-to-live-ttl-streams.html
{ 'Records':[ { ... 'userIdentity':{ 'principalId':'dynamodb.amazonaws.com', 'type':'Service' }, ... } ] }
今回の解決策
Lambda(Python)では、TTLでレコードが削除されたケースのイベント(上記の userIdentity
を含む)は、このようにフィルタリングできました。
ご参考までに。
def lambda_handler(event, context): records = event['Records'] for record in records: event_name = record['eventName'] if event_name == 'REMOVE' and record.get('userIdentity'): if record['userIdentity']['type'] == 'Service' and record['userIdentity']['principalId'] == 'dynamodb.amazonaws.com': # TTLでレコードが削除されたケースのハンドリング