タイトルの通りです。はい。
AWS Lambdaでは関数あたり最大15分(900秒)の処理が実行できます。
そして、いまやコンテナイメージもサポートしてるようです。
コンテナイメージをサポートした、といってもこれまで通りのハンドラ関数は必要なのですが、 だとしてもこれは結構便利じゃないかしら、と思ったのです。
PythonでLambda関数を作ろうとすると、virtualenvとか使って必要なライブラリと合わせてzipにパッケージングするみたいな手順が必要だったと思いますが、このパッケージング作業をDockerfileにまとめることができる。ついでに(?)開発環境と実行環境を統一できちゃう。
さらに、sam cliでプロジェクトのテンプレがさくっと作れるのでとってもイージー。
$ sam init
Which template source would you like to use?
1 - AWS Quick Start Templates
2 - Custom Template Location
Choice: 1
What package type would you like to use?
1 - Zip (artifact is a zip uploaded to S3)
2 - Image (artifact is an image uploaded to an ECR image repository)
Package type: 2
Which base image would you like to use?
1 - amazon/nodejs14.x-base
2 - amazon/nodejs12.x-base
3 - amazon/nodejs10.x-base
4 - amazon/python3.8-base
5 - amazon/python3.7-base
6 - amazon/python3.6-base
7 - amazon/python2.7-base
8 - amazon/ruby2.7-base
9 - amazon/ruby2.5-base
10 - amazon/go1.x-base
11 - amazon/java11-base
12 - amazon/java8.al2-base
13 - amazon/java8-base
14 - amazon/dotnet5.0-base
15 - amazon/dotnetcore3.1-base
16 - amazon/dotnetcore2.1-base
Base image: 4
Project name [sam-app]: my_batch_function
Cloning app templates from https://github.com/aws/aws-sam-cli-app-templates
AWS quick start application templates:
1 - Hello World Lambda Image Example
2 - PyTorch Machine Learning Inference API
3 - Scikit-learn Machine Learning Inference API
4 - Tensorflow Machine Learning Inference API
5 - XGBoost Machine Learning Inference API
Template selection: 1
-----------------------
Generating application:
-----------------------
Name: my_batch_function
Base Image: amazon/python3.8-base
Dependency Manager: pip
Output Directory: .
Next steps can be found in the README file at ./my_batch_function/README.md
$ tree .
.
└── my_batch_function
├── README.md
├── __init__.py
├── events
│ └── event.json
├── hello_world
│ ├── Dockerfile
│ ├── __init__.py
│ ├── app.py
│ └── requirements.txt
├── template.yaml
└── tests
├── __init__.py
└── unit
├── __init__.py
└── test_handler.py
さて、上記手順で作成するとテンプレートは API Gateway -> Lambda という普通の構成で作成されるのですが、
定期バッチ処理としては、
EventBridge(cron) -> SQS -> Lambda
という感じで定義しておくと、いざというときの手動実行にも対応できるので良さそうです。
(※バッチ処理のキックをAPIとして公開して外部サービスからコントロールしたいなどの要求があるなら、たとえば IFTTT -> API Gateway -> Lambdaとかでも良いかもしれません)
書き換えたテンプレートはこんな感じです。
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: my_batch_function
Globals:
Function:
Timeout: 900
Environment:
Variables:
API_KEY: '****'
Resources:
MyFunction:
Type: AWS::Serverless::Function
Properties:
PackageType: Image
MemorySize: 512
Events:
MySQSEvent:
Type: SQS
Properties:
Queue: !GetAtt MySqsQueue.Arn
BatchSize: 1
Metadata:
Dockerfile: Dockerfile
DockerContext: './my_batch_function'
DockerTag: python3.8-v1
MySqsQueue:
Type: AWS::SQS::Queue
Properties:
VisibilityTimeout: 900
MessageRetentionPeriod: 3600
MyQueuePolicy:
Type: AWS::SQS::QueuePolicy
Properties:
PolicyDocument:
Id: !Ref MySqsQueue
Statement:
- Sid: QueuePolicy-MySqsQueue
Effect: Allow
Principal: '*'
Action: 'SQS:*'
Resource:
!GetAtt MySqsQueue.Arn
Queues:
- !Ref MySqsQueue
MyEventRule:
Type: AWS::Events::Rule
Properties:
Name: myBatchFunctionCron
ScheduleExpression: 'cron(0 0 ? * SUN *)'
State: ENABLED
Targets:
- Arn: !GetAtt MySqsQueue.Arn
Id: myBatchFunctionSchedule
Input: |
{
"type": "cron",
"params": ["hoge", "fuga"]
}
- Lambda関数のMemorySizeは128でも動くのですが、処理時間見合で上げた方が良いかも
- EventBridgeのRuleにバッチ処理で使用するデータをJSONを定義しておくと便利
- バッチ起動用のQueueはMessageRetentionPeriodを絞っておくと、失敗時に必要以上にリトライしちゃうのを減らせるかも(※ちゃんとデッドレターキューを定義するのが良いと思う)
- Lambda関数のBatchSizeは1で良いと思う。(SQSの場合のデフォルトは10ですが、1回あたりの処理時間が最大900秒なので1メッセージ1処理で設計した方が確実)