はじめに
今回は AWS CloudWatch Events を試します。
スケジュールをcron式で設定し、Lambda関数を実行するページを作成します。
[Lambda関数・SAMテンプレート]
(https://github.com/tanaka-takurou/serverless-application-cron-page-go)
準備
[AWS CloudWatch Eventsの資料]
AWS CloudWatch Events
AWS SAM テンプレート作成
AWS SAM テンプレートで API-Gateway , Lambda, CloudWatch Eventsの設定をします。
[参考資料]
AWS SAM テンプレートを作成する
template.yml
template.yml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Serverless Application Cron
Parameters:
ApplicationName:
Type: String
Default: 'ServerlessApplicationCron'
CronEventRuleName:
Type: String
Default: 'CronEventRule'
CronMainFunctionName:
Type: String
Default: 'CronMainFunction'
FrontPageApiStageName:
Type: String
Default: 'ProdStage'
Metadata:
AWS::ServerlessRepo::Application:
Name: Serverless-Application-Cron
Description: 'This application is test for CloudWatch Events.'
Author: tanaka-takurou
SpdxLicenseId: MIT
LicenseUrl: LICENSE.txt
ReadmeUrl: README.md
Labels: ['ServerlessRepo']
HomePageUrl: https://github.com/tanaka-takurou/serverless-application-cron-page-go
SemanticVersion: 0.0.1
SourceCodeUrl: https://github.com/tanaka-takurou/serverless-application-cron-page-go
Resources:
FrontPageApi:
Type: AWS::Serverless::Api
Properties:
EndpointConfiguration: REGIONAL
StageName: !Ref FrontPageApiStageName
FrontPageFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: bin/
Handler: main
MemorySize: 256
Runtime: go1.x
Description: 'Cron Front Function'
Events:
FrontPageApi:
Type: Api
Properties:
Path: '/'
Method: get
RestApiId: !Ref FrontPageApi
Environment:
Variables:
REGION: !Ref 'AWS::Region'
API_PATH: !Join [ '', [ '/', !Ref FrontPageApiStageName, '/api'] ]
MainFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Ref CronMainFunctionName
CodeUri: api/bin/
Handler: main
MemorySize: 256
Runtime: go1.x
Description: 'Cron API Function'
Policies:
- Statement:
- Effect: 'Allow'
Action:
- 'logs:CreateLogGroup'
- 'logs:CreateLogStream'
- 'logs:PutLogEvents'
Resource: '*'
- Effect: 'Allow'
Action:
- 'lambda:*'
- 'events:DescribeRule'
- 'events:PutRule'
Resource: '*'
Environment:
Variables:
LAST_EVENT: ""
EVENT_NAME: !Ref CronEventRuleName
FUNCTION_NAME: !Ref CronMainFunctionName
REGION: !Ref 'AWS::Region'
Events:
FrontPageApi:
Type: Api
Properties:
Path: '/api'
Method: post
RestApiId: !Ref FrontPageApi
CronApiPermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: !Ref MainFunction
Principal: apigateway.amazonaws.com
CronEventRule:
Type: AWS::Events::Rule
Properties:
Name: !Ref CronEventRuleName
Description: CronRule
ScheduleExpression: 'cron(0 12 * * ? *)'
State: 'ENABLED'
Targets:
- Arn: !GetAtt MainFunction.Arn
Id: TargetCronFunction
PermissionForEventsToInvokeLambda:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !Ref MainFunction
Action: 'lambda:InvokeFunction'
Principal: 'events.amazonaws.com'
SourceArn: !GetAtt CronEventRule.Arn
Outputs:
APIURI:
Value: !Join [ '', [ 'https://', !Ref FrontPageApi, '.execute-api.',!Ref 'AWS::Region','.amazonaws.com/',!Ref FrontPageApiStageName,'/'] ]
CloudWatch Eventsの設定は以下の部分
CronEventRule:
Type: AWS::Events::Rule
Properties:
Name: !Ref CronEventRuleName
Description: CronRule
ScheduleExpression: 'cron(0 12 * * ? *)'
State: 'ENABLED'
Targets:
- Arn: !GetAtt MainFunction.Arn
Id: TargetCronFunction
PermissionForEventsToInvokeLambda:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !Ref MainFunction
Action: 'lambda:InvokeFunction'
Principal: 'events.amazonaws.com'
SourceArn: !GetAtt CronEventRule.Arn
Lambda関数作成
※ Lambda関数は aws-lambda-go を利用し、CloudWatch Events周りの処理は aws-sdk-go-v2 を利用しました。
AWS SDK for Go API Reference V2
ルールを追加・更新するには PutRule を使う
func putRule(ctx context.Context, minute string, hour string, day string, month string, year string) error {
var m_ int
var h_ int
var d_ int
var o_ int
var y_ int
m_, _ = strconv.Atoi(minute)
h_, _ = strconv.Atoi(hour)
d_, _ = strconv.Atoi(day)
o_, _ = strconv.Atoi(month)
y_, _ = strconv.Atoi(year)
if m_ < 0 {
m_ = 0
}
sm := strconv.Itoa(m_)
if h_ < 0 {
h_ = 0
}
sh := strconv.Itoa(h_)
sd := "*"
if d_ > 0 {
sd = strconv.Itoa(d_)
}
so := "*"
if o_ > 0 {
so = strconv.Itoa(o_)
}
sy := "*"
if y_ >= 1970 {
sy = strconv.Itoa(y_)
}
if cloudwatcheventsClient == nil {
cloudwatcheventsClient = getCloudwatcheventsClient()
}
params := &cloudwatchevents.PutRuleInput{
Name: aws.String(os.Getenv("EVENT_NAME")),
ScheduleExpression: aws.String("cron(" + sm + " " + sh + " " + sd + " " + so + " ? " + sy + ")"),
}
res, err := cloudwatcheventsClient.PutRule(ctx, params)
if err != nil {
log.Print(err)
return err
}
log.Printf("%+v\n", res)
return nil
}
ルールの内容を取得するには DescribeRule を使う
func describeRule(ctx context.Context)(string, error) {
if cloudwatcheventsClient == nil {
cloudwatcheventsClient = getCloudwatcheventsClient()
}
params := &cloudwatchevents.DescribeRuleInput{
Name: aws.String(os.Getenv("EVENT_NAME")),
}
res, err := cloudwatcheventsClient.DescribeRule(ctx, params)
if err != nil {
log.Print(err)
return "", err
}
return stringValue(res.ScheduleExpression), nil
}
終わりに
cron式で指定するタイムゾーンはUTCのため、時差を考慮する必要があります。
Lambda関数以外も CloudWatch Eventから実行できるため、今後試していこうと思います。
参考資料
[Amazon CloudWatch Events で cron 式を使う場合は時差に気をつける](https://qiita.com/niwasawa/items/6e0b191d6aa21213c7ec)
[CloudWatch Eventについての整理・備忘録](https://qiita.com/RyoMa_0923/items/61b67e12fb8aebd08241)
[CloudFormationでCloudWatch EventsとLambdaを構築](https://qiita.com/tomoki_s/items/d23cd5eca26f7d778b73)
[ルールのスケジュール式](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/events/ScheduledEvents.html)