Most tutorials skip a detail: an AWS Glue job is not a native target for an EventBridge rule. If you open the target dropdown, you’ll find Glue workflow, not Glue job.
So “trigger a Glue job from EventBridge” really means one of three patterns. Each has different IAM, different semantics, and different failure modes.
| Pattern | Use when | EventBridge role needs |
|---|---|---|
| Rule → Glue workflow (EVENT trigger) | Event-driven (S3 object created, custom events) | glue:notifyEvent |
EventBridge Scheduler → startJobRun | Time-based (cron/rate) | glue:StartJobRun |
| Rule → Step Functions → Glue | You need retries, waiting, chaining, notifications | states:StartExecution |
Pattern 1: EventBridge rule → Glue workflow
The workflow’s starting trigger must be of type EVENT. The job runs as an action of that trigger.
$ aws glue create-workflow --name ingest-events-wf
$ aws glue create-trigger \
--name ingest-events-start \
--workflow-name ingest-events-wf \
--type EVENT \
--event-batching-condition BatchSize=1,BatchWindow=900 \
--actions JobName=ingest-events
BatchSize=1 starts the workflow on every event. Increase it to batch multiple S3 uploads into a single run. The workflow starts when either BatchSize events arrive or BatchWindow seconds pass.
If the job uses bookmarks, be careful with BatchSize=1 and MaxConcurrentRuns > 1: a burst of uploads can start overlapping runs that read the same bookmark state. See Debugging AWS Glue Job Bookmarks Not Working as Expected.
For S3 events, the bucket must send notifications to EventBridge. This is off by default:
$ aws s3api put-bucket-notification-configuration \
--bucket my-raw-bucket \
--notification-configuration '{"EventBridgeConfiguration": {}}'
The rule:
{
"source": ["aws.s3"],
"detail-type": ["Object Created"],
"detail": {
"bucket": { "name": ["my-raw-bucket"] },
"object": { "key": [{ "prefix": "events/" }] }
}
}
IAM for pattern 1
The target needs a role EventBridge can assume. Trust policy:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "Service": "events.amazonaws.com" },
"Action": "sts:AssumeRole"
}]
}
Permissions policy: glue:notifyEvent, not glue:StartJobRun. This is the most common mistake.
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "glue:notifyEvent",
"Resource": "arn:aws:glue:us-east-1:123456789012:workflow/ingest-events-wf"
}]
}
Attach the target:
$ aws events put-targets --rule s3-events-to-glue --targets \
'Id=glue-wf,Arn=arn:aws:glue:us-east-1:123456789012:workflow/ingest-events-wf,RoleArn=arn:aws:iam::123456789012:role/eb-to-glue-wf'
The job itself still runs with its own Glue job role. EventBridge’s role only needs permission to notify the workflow.
To check whether the triggered run actually succeeded, see How to Get the Status of an AWS Glue Workflow Using boto3.
Pattern 2: EventBridge Scheduler → startJobRun
For time-based runs, EventBridge Scheduler supports universal targets: it can call almost any AWS API directly. No Lambda, no workflow.
$ aws scheduler create-schedule \
--name nightly-ingest \
--schedule-expression "cron(0 3 * * ? *)" \
--schedule-expression-timezone "America/Argentina/Buenos_Aires" \
--flexible-time-window Mode=OFF \
--target '{
"Arn": "arn:aws:scheduler:::aws-sdk:glue:startJobRun",
"RoleArn": "arn:aws:iam::123456789012:role/scheduler-to-glue",
"Input": "{\"JobName\": \"ingest-events\", \"Arguments\": {\"--run_mode\": \"nightly\"}}"
}'
Input is the request body of the StartJobRun API, so you can pass job arguments directly.
IAM for pattern 2
Trust scheduler.amazonaws.com:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "Service": "scheduler.amazonaws.com" },
"Action": "sts:AssumeRole"
}]
}
Permissions:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "glue:StartJobRun",
"Resource": "arn:aws:glue:us-east-1:123456789012:job/ingest-events"
}]
}
If you only need a schedule, a native Glue SCHEDULED trigger also works. Scheduler wins when you want time zones, one-off schedules, or a single place for all schedules across services.
Pattern 3: Rule → Step Functions → Glue
When you need more than “start the job” (wait for completion, retry on failure, notify on error, chain a crawler), put Step Functions in between. The .sync integration waits for the job to finish:
{
"StartAt": "RunGlueJob",
"States": {
"RunGlueJob": {
"Type": "Task",
"Resource": "arn:aws:states:::glue:startJobRun.sync",
"Parameters": { "JobName": "ingest-events" },
"Retry": [{
"ErrorEquals": ["States.ALL"],
"MaxAttempts": 2,
"BackoffRate": 2
}],
"End": true
}
}
}
IAM for pattern 3
Two roles:
- EventBridge → Step Functions: trust
events.amazonaws.com, allowstates:StartExecutionon the state machine. - State machine role: for
.sync, allowglue:StartJobRun,glue:GetJobRun,glue:GetJobRuns, andglue:BatchStopJobRunon the job.
Missing glue:GetJobRun is a classic: the job starts, then the execution fails because Step Functions can’t poll the status.
Debugging checklist
- Rule matches but nothing runs: check the rule’s
FailedInvocationsmetric in CloudWatch. It usually means the target role can’t be assumed or lacks permission. - Pattern 1, no events at all: S3 → EventBridge notifications not enabled on the bucket.
- Pattern 1, workflow starts late:
BatchWindowis doing its job. Lower it or setBatchSize=1. AccessDeniedon the job’s S3 reads: that’s the Glue job role, not the EventBridge/Scheduler role.- Add a dead-letter queue (SQS) to the target so failed invocations are visible.