
Powertools for AWS Lambda (Python) の Feature flags を使って「時間ベースフィーチャーフラグ (Time based feature flags)」を試してみた.Powertools for AWS Lambda (Python) の Feature flags はデフォルトだと AWS AppConfig をバックエンドにしていて,時間ベース以外に文字列部分一致・数値範囲など柔軟に条件をしてフラグ制御 (true or false) ができる👌
検証環境
アプリケーション (AWS Lambda) とフィーチャーフラグ (AWS AppConfig) は運用上ライフサイクルが異なるため別のスタックにした.
├── application
│ ├── src
│ │ └── app.py
│ └── template.yaml
└── features
└── template.yaml
1. features
まず AWS AppConfig をデプロイする.Powertools ドキュメントを参考に AWS CloudFormation テンプレートを書いた.ちなみに Powertools ドキュメントに載っているサンプルだと AWS AppConfig のデプロイ戦略にビルトインの AppConfig.AllAtOnce が指定されていた📝これは即時デプロイをしたら10分間待つ戦略で (BakeTime 10 minutes) 今回はサクサクと検証をしたく,BakeTime なしのカスタムデプロイ戦略を追加した💡
- AWS::AppConfig::Application - AWS CloudFormation
- AWS::AppConfig::Environment - AWS CloudFormation
- AWS::AppConfig::ConfigurationProfile - AWS CloudFormation
- AWS::AppConfig::HostedConfigurationVersion - AWS CloudFormation
- AWS::AppConfig::DeploymentStrategy - AWS CloudFormation
- AWS::AppConfig::Deployment - AWS CloudFormation
そして HostedConfigurationVersion に時間ベースフィーチャーフラグ (Time based feature flags) を設定した.今回はサンプルとして開始時間と終了時間が決まっているキャンペーン(campaign-a と campaign-b)の制御をする❗️
- campaign-a:
2024-07-06T12:00:00~2024-07-06T12:29:59 - campaign-b:
2024-07-06T12:30:00~2024-07-06T12:59:59
ちなみに時間ベースだと,他には「毎日◯時〜◯時」や「毎週◯曜日」という設定もできる📅
AWSTemplateFormatVersion: 2010-09-09 Resources: Application: Type: AWS::AppConfig::Application Properties: Name: sandbox Environment: Type: AWS::AppConfig::Environment Properties: Name: prd ApplicationId: !Ref Application ConfigurationProfile: Type: AWS::AppConfig::ConfigurationProfile Properties: Name: profile ApplicationId: !Ref Application LocationUri: hosted HostedConfigurationVersion: Type: AWS::AppConfig::HostedConfigurationVersion Properties: ApplicationId: !Ref Application ConfigurationProfileId: !Ref ConfigurationProfile ContentType: application/json Content: | { "campaign-a": { "default": false, "rules": { "Enable Campaign A": { "when_match": true, "conditions": [ { "action": "SCHEDULE_BETWEEN_DATETIME_RANGE", "key": "CURRENT_DATETIME", "value": { "START": "2024-07-06T12:00:00", "END": "2024-07-06T12:29:59", "TIMEZONE": "Asia/Tokyo" } } ] } } }, "campaign-b": { "default": false, "rules": { "Enable Campaign B": { "when_match": true, "conditions": [ { "action": "SCHEDULE_BETWEEN_DATETIME_RANGE", "key": "CURRENT_DATETIME", "value": { "START": "2024-07-06T12:30:00", "END": "2024-07-06T12:59:59", "TIMEZONE": "Asia/Tokyo" } } ] } } } } DeploymentStrategy: Type: AWS::AppConfig::DeploymentStrategy Properties: Name: Custom.AllAtOnce DeploymentDurationInMinutes: 0 GrowthFactor: 100 FinalBakeTimeInMinutes: 0 ReplicateTo: NONE Deployment: Type: AWS::AppConfig::Deployment Properties: ApplicationId: !Ref Application EnvironmentId: !Ref Environment ConfigurationProfileId: !Ref ConfigurationProfile ConfigurationVersion: !Ref HostedConfigurationVersion DeploymentStrategyId: !Ref DeploymentStrategy
ちなみに AWS AppConfig 自体のフィーチャーフラグとは関係なく,AWS AppConfig をバックエンドにした Powertools for AWS Lambda (Python) の仕組みになる.コンソールだと 自由形式の設定プロファイル となる.少しややこしい😇

2. application
次は AWS Lambda をデプロイする.AWS SAM テンプレートで Powertools Layer を設定しておく.あと IAM Role に AWS AppConfig を操作する権限を付けておく.Powertools ドキュメントには appconfig:GetLatestConfiguration と appconfig:StartConfigurationSession で十分と書いてあった✅
AWSTemplateFormatVersion: 2010-09-09 Transform: AWS::Serverless-2016-10-31 Resources: Function: Type: AWS::Serverless::Function Properties: FunctionName: powertools-feature-flags-time-based CodeUri: src/ Handler: app.lambda_handler Runtime: python3.12 Architectures: - x86_64 Layers: - arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:75 Role: arn:aws:iam::000000000000:role/xxxxx
コードでは Powertools for AWS Lambda (Python) の Feature flags で evaluate() を実行して,結果を表示するシンプルな実装にした👌
from aws_lambda_powertools.utilities.feature_flags import AppConfigStore, FeatureFlags app_config = AppConfigStore(application='sandbox', environment='prd', name='profile') feature_flags = FeatureFlags(store=app_config) def lambda_handler(event, context): campaign_a = feature_flags.evaluate(name='campaign-a', default=False) campaign_b = feature_flags.evaluate(name='campaign-b', default=False) features = { 'campaign-a': campaign_a, 'campaign-b': campaign_b, } print(features)
動作確認
計4回実行してみた🕐
期待通りの結果になったー \( 'ω')/
👇 11:50
{'campaign-a': False, 'campaign-b': False}
👇 12:10
{'campaign-a': True, 'campaign-b': False}
👇 12:40
{'campaign-a': False, 'campaign-b': True}
👇 13:10
{'campaign-a': False, 'campaign-b': False}
フィーチャーフラグのキャッシュ機能
Powertools for AWS Lambda (Python) の Feature flags は毎回 AWS AppConfig から取得するのではなく,デフォルトでは「5秒間」キャッシュされる📂AWS Lambda 関数のライフサイクルとして,初期化後にもフィーチャーフラグを更新できる👌
AWS AppConfig の呼び出し回数を減らすこととフィーチャーフラグの鮮度を高めることのトレードオフにはなるけど,もしキャッシュ時間を変更する場合は AppConfigStore で初期化するときに max_age を設定して変更できる.
app_config = AppConfigStore(application='sandbox', environment='prd', name='profile', max_age=30)
単体テスト
Powertools ドキュメントには pytest-mock を使って AWS AppConfig に依存せずテストをするサンプル実装が載っていた.LocalStack も AWS AppConfig をサポートしているけど,LocalStack Pro で使えるため,契約が必要になってしまう💨