Automation
Azure Container Apps Jobs : diagnostiquer une règle KEDA avant de relancer les workers
Un runbook de production pour qualifier un Azure Container Apps Job qui ne consomme plus correctement avec règle KEDA, backlog, identité managée, secrets, logs, idempotence, validation et rollback avant de relancer les workers.
Un Azure Container Apps Job qui ne consomme plus une queue ressemble vite à un simple problème de workers. La tentation est de relancer le job, d’augmenter le parallélisme ou de purger les messages bloqués. C’est dangereux si le vrai problème vient de la règle KEDA, d’une identité qui ne lit plus la queue, d’un secret expiré, d’un profil de charge saturé, d’une image cassée ou d’un traitement non idempotent.
Le cas d’usage est un job invoice-worker-prod déclenché par backlog sur une queue. Depuis un déploiement, le backlog monte, quelques exécutions passent en erreur, et l’équipe veut relancer les workers pour rattraper le retard. Avant de rejouer, il faut décider si l’action sûre est une correction de règle KEDA, une restauration de secret, un rollback de l’image, une réduction du parallélisme, un replay borné ou une pause volontaire de la consommation.
Figurer le job comme un contrat de consommation
Commencez par écrire ce que le job doit consommer et ce qu’il ne doit pas casser. Une règle KEDA n’est pas seulement un seuil. Elle relie une source d’événements, une identité, des métadonnées, une limite de parallélisme et un code applicatif qui doit supporter les retries.
job:
name: invoice-worker-prod
environment: aca-env-prod
resource_group: rg-app-prod
trigger: event_driven
workload_profile: consumption-prod
source:
type: storage_queue
account: stprodops
queue: invoices-to-process
expected_backlog_behavior: decreases_during_business_hours
poison_queue: invoices-to-process-poison
scale_rule:
name: invoices-queue
min_executions: 0
max_executions: 20
polling_interval_seconds: 30
message_threshold: 25
runtime_contract:
idempotency_key: invoice_id
retry_safe_until: before_external_payment_capture
managed_identity: aca-invoice-worker-prod
secrets:
- queue_connection_or_identity_binding
- downstream_api_token_reference
blocked_until_proven:
- backlog_shape_known
- keda_rule_current
- identity_can_read_queue
- latest_image_healthy
- replay_scope_bounded
- rollback_path_ready Ce contrat évite de traiter la queue comme un simple compteur. Si le traitement n’est pas idempotent après une étape externe, un replay large peut créer plus d’incident que le backlog initial.
Lire le backlog avant de relancer
Le premier diagnostic porte sur la forme du backlog. Une montée continue peut indiquer que KEDA ne déclenche plus. Des messages anciens et peu nombreux peuvent indiquer un poison message. Des vagues de retries peuvent venir d’un downstream en erreur. Une queue vide avec des alertes de retard peut simplement signaler une observabilité en décalage.
Backlog a qualifier
Nombre de messages visibles
Age du plus ancien message
Nombre de messages dequeue plusieurs fois
Messages transferes en poison queue
Heure du dernier message consomme avec succes
Correlation avec le dernier deploiement
Interpretation possible
Backlog monte sans executions: regarder KEDA, identite, metadata de trigger
Executions nombreuses en echec: regarder image, code, secrets, downstream
Quelques messages repetes: isoler poison messages avant replay global
Backlog intermittent: verifier workload profile, quotas et cold start La décision de relance dépend de cette lecture. On ne rejoue pas une queue entière quand le symptôme réel est concentré sur trois messages invalides ou sur une API aval indisponible.
Comparer la règle KEDA déclarée et effective
La configuration utile est celle que Container Apps voit maintenant. Vérifiez le job, son type de trigger, les scale rules, les secrets référencés et les limites d’exécution avant de modifier le code ou d’augmenter maxExecutions.
RG="rg-app-prod"
JOB="invoice-worker-prod"
az containerapp job show --resource-group "$RG" --name "$JOB" --query "{trigger:properties.configuration.triggerType, replicaTimeout:properties.configuration.replicaTimeout, replicaRetryLimit:properties.configuration.replicaRetryLimit, parallelism:properties.configuration.parallelism, replicaCompletionCount:properties.configuration.replicaCompletionCount, scaleRules:properties.configuration.eventTriggerConfig.scale.rules, registries:properties.configuration.registries}" --output json
az containerapp job execution list --resource-group "$RG" --name "$JOB" --output table Cherchez les dérives simples : nom de queue modifié, seuil trop haut, secret renommé, identité retirée, limite d’exécutions trop basse, timeout trop court, ou profil de charge différent de celui attendu.
Séparer déclenchement et exécution
Un job peut ne pas démarrer parce que KEDA ne sait pas lire la source. Il peut aussi démarrer correctement puis échouer dans le conteneur. Ces deux états appellent des corrections différentes.
Probleme de declenchement
Aucune execution alors que le backlog monte
Erreurs d'authentification sur la source d'evenements
Scale rule absente ou metadata incoherente
Secret ou identity binding introuvable
Probleme d'execution
Executions creees puis Failed
Logs applicatifs avec exception metier ou downstream
Pull image ou startup probe en echec
Timeout avant fin de traitement
Retries qui retraitent le meme message
Decision
Corriger KEDA ou l'identite si le job ne demarre pas
Corriger image, code, secret ou downstream si le job demarre puis echoue
Ne pas augmenter le scale-out tant que la classe du probleme n'est pas claire Cette séparation protège la production contre une fausse bonne idée : augmenter la concurrence alors que chaque worker échoue pour la même raison.
Lire les logs avec une fenêtre bornée
Les logs doivent répondre à trois questions : le scaler a-t-il déclenché, le conteneur a-t-il démarré, et le message a-t-il été traité ou rejeté ? Adaptez les tables au mode Log Analytics réellement activé dans l’environnement.
let StartTime = datetime(2026-07-30T06:00:00Z);
let EndTime = datetime(2026-07-30T09:00:00Z);
let JobName = "invoice-worker-prod";
ContainerAppSystemLogs_CL
| where TimeGenerated between (StartTime .. EndTime)
| where ContainerAppName_s == JobName
| project TimeGenerated, Reason_s, Log_s, ReplicaName_s
| union (
ContainerAppConsoleLogs_CL
| where TimeGenerated between (StartTime .. EndTime)
| where ContainerAppName_s == JobName
| project TimeGenerated, Reason_s="console", Log_s, ReplicaName_s
)
| order by TimeGenerated desc Si les logs ne montrent rien, ce n’est pas une preuve que le job est sain. Vérifiez d’abord Diagnostic Settings, workspace cible, délai d’ingestion et nom réel du job ou de l’exécution.
Valider identité, secrets et accès à la source
Une règle KEDA peut dépendre d’un secret ou d’une identité managée. Un changement RBAC, une rotation de secret ou une modification Key Vault peut empêcher la lecture du backlog sans que le code applicatif ait changé.
Identite et acces
Identite managée attendue attachee au job
Role minimal sur la queue ou le namespace
Aucun deny assignment ou policy recente
Secret reference toujours resolue
Key Vault accessible depuis l'environnement Container Apps si utilise
Expiration ou rotation recente documentee
Preuves utiles
Erreurs 401/403 dans logs systeme ou applicatifs
Dernier succes avant rotation
Comparaison avec un job sain sur la meme source
Scope RBAC exact plutot que role elargi au subscription Ne remplacez pas une identité managée par une connection string durable pour aller vite. Si un secret temporaire est nécessaire pour restauration, il doit avoir une durée, un propriétaire et un retrait prévu.
Choisir replay, correction ou pause
Après les preuves, la décision doit être explicite. Un replay manuel est acceptable seulement si le traitement est idempotent, si le périmètre est borné et si la cause est corrigée ou contournée proprement.
Corriger la regle KEDA
Backlog present, aucune execution, metadata ou secret de scaler en derive
Rollbacker l'image ou la configuration
Executions recentes echouent apres un deploiement applicatif ou IaC
Reduire le parallellisme
Downstream degrade, workers trop nombreux, retries amplifient l'incident
Isoler poison messages
Petit nombre de messages repetes, erreurs fonctionnelles reproductibles
Relancer manuellement
Cause corrigee, idempotence prouvee, fenetre et volume bornes, validation prete
Pause volontaire
Traitement non idempotent ou downstream encore instable La bonne action peut être de ne pas consommer pendant quelques minutes. Une pause contrôlée avec backlog surveillé vaut mieux qu’un replay qui écrit deux fois dans un système aval.
Valider et préparer le rollback
La clôture doit prouver que la consommation reprend sans masquer la cause. Gardez une validation applicative, pas seulement une baisse de backlog.
Validation finale
La regle KEDA observe la bonne source
Les executions recentes passent en Succeeded
Le backlog baisse au rythme attendu
Aucun poison message nouveau n'apparait
Les logs montrent l'idempotency key ou la correlation metier
Le downstream confirme les traitements attendus
Rollback
Revenir a l'image ou revision precedente du job
Restaurer la precedente scale rule depuis IaC
Remettre le seuil et le parallellisme initiaux
Revoquer tout secret temporaire
Replacer les messages isoles seulement apres correction
Documenter les messages non rejoues Si une modification manuelle a été faite dans l’urgence, elle reste provisoire jusqu’à retour dans l’IaC ou suppression explicite.
Conclusion
Un Azure Container Apps Job bloqué n’est pas seulement un worker à relancer. C’est une chaîne de consommation : source d’événements, règle KEDA, identité, secrets, image, limites d’exécution, logs, idempotence et système aval.
La décision utile est donc bornée : corriger le scaler si le job ne démarre pas, rollbacker l’image si les exécutions échouent depuis le déploiement, réduire la concurrence si le downstream souffre, isoler les messages invalides, ou relancer seulement après preuve d’idempotence. Le runbook transforme un backlog urgent en reprise contrôlée.