09 Jobs & Background Processing
Goal
Run batch workloads with Azure Container Apps Jobs. Create a scheduled job that batch-processes the triage queue and a manual-trigger job for on-demand report generation.
Estimated time
15 minutes.
Official references
Key concepts
| Concept | Purpose |
|---|---|
| Container Apps Job | A container that runs to completion (not a long-running service). |
| Scheduled trigger | Runs on a cron schedule (e.g. nightly batch). |
| Manual trigger | Runs on demand via CLI or API. |
| Event trigger | Runs in response to events (queue messages, etc.). |
| Execution | A single run of a job — has its own logs and exit code. |
Exercise
Step 1 — Create a scheduled job
Deploy the batch worker as a scheduled job that runs at 2 AM UTC daily:
source .env
# Enable admin credentials on ACR (needed for job registry auth)
az acr update --name $ACR_NAME --admin-enabled true
az containerapp job create \
--name triage-batch-job \
--resource-group $RESOURCE_GROUP \
--environment $CONTAINERAPPS_ENVIRONMENT \
--image $ACR_NAME.azurecr.io/triage-worker:v1 \
--registry-server $ACR_NAME.azurecr.io \
--registry-username $ACR_NAME \
--registry-password "$(az acr credential show --name $ACR_NAME --query 'passwords[0].value' -o tsv)" \
--trigger-type Schedule \
--cron-expression "0 2 * * *" \
--replica-timeout 600 \
--replica-retry-limit 1 \
--cpu 0.5 \
--memory 1Gi \
--secrets "project-endpoint=$AZURE_AI_PROJECT_ENDPOINT" \
--env-vars "AZURE_AI_PROJECT_ENDPOINT=secretref:project-endpoint" \
"AZURE_AI_MODEL_DEPLOYMENT=$AZURE_AI_MODEL_DEPLOYMENT"
Step 2 — Assign managed identity and grant AI access
The job uses DefaultAzureCredential to call the AI model. Assign a
system-assigned identity and grant it the required role:
az containerapp job identity assign \
--name triage-batch-job \
--resource-group $RESOURCE_GROUP \
--system-assigned
JOB_PRINCIPAL_ID=$(az containerapp job show \
--name triage-batch-job \
--resource-group $RESOURCE_GROUP \
--query identity.principalId -o tsv)
AI_RESOURCE_ID=$(az resource list --resource-group $RESOURCE_GROUP \
--resource-type "Microsoft.CognitiveServices/accounts" --query "[0].id" -o tsv)
az role assignment create \
--assignee $JOB_PRINCIPAL_ID \
--role "Cognitive Services OpenAI User" \
--scope "$AI_RESOURCE_ID"
Info
Role assignments can take 1–2 minutes to propagate. Wait a moment before triggering the job.
Step 3 — Trigger the scheduled job manually (for testing)
Don't wait until 2 AM — start an execution now:
Step 4 — View execution history
az containerapp job execution list \
--name triage-batch-job \
--resource-group $RESOURCE_GROUP \
-o table
Step 5 — View job logs
az containerapp job logs show \
--name triage-batch-job \
--resource-group $RESOURCE_GROUP \
--container triage-batch-job \
--follow
You should see the batch triage report with urgency classifications for the sample patients.
Step 6 — Create a manual-trigger job
Create a second job that runs only when explicitly triggered — useful for on-demand reports:
az containerapp job create \
--name triage-report-job \
--resource-group $RESOURCE_GROUP \
--environment $CONTAINERAPPS_ENVIRONMENT \
--image $ACR_NAME.azurecr.io/triage-worker:v1 \
--registry-server $ACR_NAME.azurecr.io \
--registry-username $ACR_NAME \
--registry-password "$(az acr credential show --name $ACR_NAME --query 'passwords[0].value' -o tsv)" \
--trigger-type Manual \
--replica-timeout 600 \
--replica-retry-limit 1 \
--cpu 0.5 \
--memory 1Gi \
--secrets "project-endpoint=$AZURE_AI_PROJECT_ENDPOINT" \
--env-vars "AZURE_AI_PROJECT_ENDPOINT=secretref:project-endpoint" \
"AZURE_AI_MODEL_DEPLOYMENT=$AZURE_AI_MODEL_DEPLOYMENT"
# Assign identity and grant AI access (same as the batch job)
az containerapp job identity assign \
--name triage-report-job \
--resource-group $RESOURCE_GROUP \
--system-assigned
REPORT_PRINCIPAL_ID=$(az containerapp job show \
--name triage-report-job \
--resource-group $RESOURCE_GROUP \
--query identity.principalId -o tsv)
az role assignment create \
--assignee $REPORT_PRINCIPAL_ID \
--role "Cognitive Services OpenAI User" \
--scope "$AI_RESOURCE_ID"
Step 7 — Run the manual job
Step 8 — Compare execution history
# Scheduled job
az containerapp job execution list \
--name triage-batch-job \
--resource-group $RESOURCE_GROUP \
-o table
# Manual job
az containerapp job execution list \
--name triage-report-job \
--resource-group $RESOURCE_GROUP \
-o table
Step 9 — List all jobs in the environment
Jobs vs Container Apps
| Aspect | Container App | Container Apps Job |
|---|---|---|
| Lifecycle | Long-running (always on or scaled to zero) | Runs to completion, then exits |
| Trigger | HTTP requests, TCP, events | Schedule, manual, event |
| Scaling | 0–N replicas based on load | 0–N executions based on trigger |
| Use case | APIs, web apps, microservices | Batch processing, ETL, reports |
| Cost | Per-second while running | Per-second per execution |
What this lab demonstrates
- Creating scheduled and manual-trigger Container Apps Jobs.
- Running a batch AI workload (triage classification).
- Viewing execution history and logs.
- Understanding when to use Jobs vs always-on Container Apps.
Expected result
Two jobs exist in the environment. The scheduled job runs nightly (and can be triggered manually). The manual job runs on demand. Both process patient records through Microsoft Foundry and output a triage report.
Verification
- [ ]
az containerapp job list --resource-group $RESOURCE_GROUP -o tableshows both jobs. - [ ] Manual execution of
triage-batch-jobcompletes successfully. - [ ] Job logs show the batch triage report with patient classifications.
- [ ]
triage-report-jobcan be triggered and shows execution history.