こんにちは~ 浮田です。
今回は私個人の気づきをブログにして残しておきます。EventBridge Schedulerの新機能を調べていたら面白い制約に気づいたので、共有します。
もうご存じの方も多いかもしれませんが、お付き合いください。
■ はじめに
先日、AWSから「Amazon EventBridge Scheduler adds 619 new SDK API actions」というニュースが出ました。
EventBridge Schedulerに13サービス・619個のAPIアクションが追加され、カスタム統合コードなしで幅広いAWSサービスを直接スケジュール実行できるようになりました。
これを見て「お、これで色んなAPIをスケジュール化できるじゃん!」とテンション上がったんですが、公式ドキュメントを読み込んでみたら「読み取り系のAPIは呼べない」という重要な制約があることに気づきました。
最初は気づかずに「全部のAPIが対象なんだろうな」と勘違いしそうだったので、同じく勘違いしそうな人向けにメモを残しておきます。
今回の話は 「ユニバーサルターゲット(Universal Target)」 という機能の話です。
ユニバーサルターゲットは、こんなARN形式でAWSのAPIを直接指定して呼び出せる仕組みです。
arn:aws:scheduler:::aws-sdk::
例:
|
やりたいこと |
ARN |
|
SQSにメッセージを送る |
arn:aws:scheduler:::aws-sdk:sqs:sendMessage |
|
Lambda関数を呼び出す |
arn:aws:scheduler:::aws-sdk:lambda:invoke |
|
Step Functionsを開始する |
arn:aws:scheduler:::aws-sdk:sfn:startExecution |
|
EC2インスタンスを起動する |
arn:aws:scheduler:::aws-sdk:ec2:startInstances |
「サービス名」と「APIアクション名」を書くだけで色んなAPIを呼べる、汎用的な仕組みです。
今回の発表は、このユニバーサルターゲットで呼べるAPIに 13サービス・619アクションが追加された という話でした。
公式ドキュメントを読むと、しれっと 「サポートされないAPIアクション」 の章があります。
以下のプレフィックスで始まるAPIアクションは、Schedulerからは呼び出せません。
get
describe
list
poll
receive
search
scan
query
select
read
lookup
discover
validate
batchGet
batchDescribe
batchRead
transactGet
adminGet
adminList
testMigration
retrieve
testConnection
translateDocument
isAuthorized
invokeModel
つまり、例えば arn:aws:scheduler:::aws-sdk:sqs:getQueueUrl のような get で始まるAPIは Scheduler からは指定できません。
リストを眺めていると、ある法則が見えてきます。
情報を取得・検証する系のAPIが全部除外されている んです。
ちょっと考えれば腑に落ちます。
EventBridge Schedulerは 「決まった時間に何かのアクションを実行する」 ためのサービスです。
例えば「毎朝9時にEC2インスタンスのリストを取得する」というスケジュールを組んだとしても…
つまり 「読み取るだけ」のスケジュールは意味がない わけです。
読み取った結果を使って何かしたい場合は、これまで通り Lambda関数を挟んで「取得 → 処理 → 保存」 をする必要があります。
除外リストの最後の方に invokeModel があるのが地味に興味深かったです。
これは Amazon Bedrock のモデル呼び出しAPI ですね。
「スケジュールで定期的にBedrockのモデルを呼びたい」という人が一定数いるであろう中で、AWSが明示的に「これは別途Lambdaを挟んでね」と除外しているわけです。
確かに、モデルの出力をどこにも渡さずに呼ぶだけだと意味がないので、当然と言えば当然ですが、わざわざ明記されているのは「やりたがる人が多い」ということでしょうね。
雑にまとめるとこうなります。
|
プレフィックス |
Schedulerから直接呼べる? |
例 |
|
create |
✅ |
createQueue, createBucket |
|
put |
✅ |
putObject, putItem |
|
start |
✅ |
startInstances, startExecution |
|
stop |
✅ |
stopInstances |
|
delete |
✅ |
deleteObject, deleteQueue |
|
update |
✅ |
updateFunctionCode |
|
send |
✅ |
sendMessage, sendEmail |
|
publish |
✅ |
publish (SNS) |
|
invoke |
✅ |
invoke (Lambda) |
|
get |
❌ |
getObject |
|
list |
❌ |
listBuckets |
|
describe |
❌ |
describeInstances |
|
search |
❌ |
search系API全般 |
|
query |
❌ |
query (DynamoDB) |
|
scan |
❌ |
scan (DynamoDB) |
|
invokeModel |
❌ |
Bedrockのモデル呼び出し |
要するに、 書き込み・実行系は OK、読み取り系は NG という覚え方でだいたい合っています。
StartInstances は実行系なのでそのまま使えます。
例として、開発環境のEC2を朝9時に自動起動するサンプルを置いておきます。これはコスト削減の定番ですね。
bash------------------
aws scheduler create-schedule \
--name start-dev-ec2 \
--schedule-expression 'cron(0 9 * * ? *)' \
--target '{
"RoleArn": "arn:aws:iam::123456789012:role/SchedulerRole",
"Arn": "arn:aws:scheduler:::aws-sdk:ec2:startInstances",
"Input": "{\"InstanceIds\":[\"i-xxxxxxxxxxxx\"]}"
}' \
--flexible-time-window '{"Mode": "OFF"}'
--------------------------------
startInstances は start プレフィックスなので、ユニバーサルターゲットからそのまま呼べます。
ちなみに、 Input で渡すパラメータの形式は 呼び出したいAPIに依存 します。今回なら StartInstances APIのドキュメントで InstanceIds が必要だと分かるので、それをJSON文字列で渡しています。
以前はLambdaを挟むのが一般的なパターンだったが、ユニバーサルターゲットを使えばLambda不要で直接呼び出せることが増えるのはいいですね。
GetObject は読み取り系なので直接呼べません。こういうときはLambdaで包みます。
-------------------------------
import boto3
def lambda_handler(event, context):
s3 = boto3.client('s3')
# GetObjectはSchedulerから直接呼べないのでLambdaの中で実行
response = s3.get_object(Bucket='my-bucket', Key='data/report.csv')
content = response['Body'].read().decode('utf-8')
# 処理して保存
processed = content.upper()
s3.put_object(Bucket='my-bucket', Key='data/report_processed.csv', Body=processed)
------------------------------------
読み取りが絡む場合は「Lambda → 取得 → 処理 → 保存」の流れにするというのがAWSがしてほしいことなんでしょうか!
公式ドキュメントの注意書きにあった地味なハマりポイント:
The value in the universal target ARN must match the AWS SDK service identifier for the target service. This identifier can differ from the service's endpoint prefix.
ARN内の 部分は、SDK識別子で書く必要があり、エンドポイントのプレフィックスとは違うことがある という話です。
例として挙げられていたのが Amazon Cognito Identity Provider で、
最初の指定で動かなくて、調べたら違う識別子だった…ということがありそうなので、サービスを指定するときは AWS SDK のドキュメントで正確な識別子を確認 したほうが安全です。
「619アクション追加!」だけ見て飛びつくと、いざ使うときに「あれ、このAPI呼べないじゃん」となるので、自分の使いたいAPIが対応しているか 公式ドキュメントの除外プレフィックスリストで先に確認する のがおすすめです。
何か作るときは「定期実行したい処理が書き込み系か、読み取り系か」を意識すると、Scheduler単体で完結するか、Lambdaが必要かの判断がしやすくなりそうですね。