Infrastructure

Azure Service Bus : réparer une trace distribuée cassée avant de redéployer

Un runbook de production pour retrouver une corrélation Application Insights et OpenTelemetry perdue au passage d’Azure Service Bus, qualifier propagation W3C, sampling et consommation, puis valider ou rollbacker la correction.

01 août 2026 azureservice-busapplication-insightsopentelemetrydistributed-tracingobservabilitykqlrunbookrollbackproduction

Une API accepte une commande, publie un message dans Azure Service Bus et répond 202. Quelques secondes plus tard, un worker échoue sur une dépendance. Dans Application Insights, la requête HTTP est verte et l’exception du worker existe, mais aucune trace ne relie les deux. L’incident devient alors une enquête par horodatage, alors que le système possède déjà les identifiants nécessaires pour reconstruire le chemin.

Le cas d’usage est une chaîne asynchrone instrumentée avec Application Insights ou OpenTelemetry : API productrice, queue ou topic Service Bus, consommateur et dépendances aval. Le but du runbook est de distinguer une vraie rupture de contexte d’un défaut d’ingestion ou de sampling, puis de corriger la propagation sans modifier le contrat métier du message ni redéployer toute la plateforme.

Figer un seul parcours asynchrone

Commencez avec un message de test identifiable. Une fenêtre temporelle et un nom de queue ne suffisent pas quand plusieurs producteurs écrivent au même endroit. Capturez le contrat de corrélation avant de toucher à l’instrumentation.

text trace-correlation-contract.txt
Parcours a qualifier
Producteur: orders-api
Entree: POST /orders
Entite Service Bus: orders.commands
Consommateur: orders-worker
Dependances aval: SQL, API de paiement, stockage
MessageId du canary: trace-canary-20260801-001
CorrelationId metier: order-test-8472
Heure UTC de publication et de consommation
Version producteur et consommateur

Preuves attendues
Une trace W3C avec trace ID stable
Un span d'envoi Service Bus
Un span de traitement cote worker
Le MessageId visible dans logs producteur et consommateur
Les dependances aval rattachees au traitement
Une decision de correction, maintien ou rollback

N’utilisez pas une commande client réelle pour le canary. Choisissez une charge sans effet métier, ou arrêtez le scénario avant toute écriture irréversible.

Séparer rupture de trace et absence de télémétrie

Trois pannes se ressemblent dans le portail : le contexte n’est pas propagé, le worker n’émet pas de télémétrie, ou les spans existent mais sont échantillonnés ou ingérés dans un autre workspace. Vérifiez d’abord que chaque segment existe indépendamment.

kusto 01-find-canary-across-tables.kql
let StartTime = datetime(2026-08-01T06:00:00Z);
let EndTime = datetime(2026-08-01T07:00:00Z);
let Canary = "trace-canary-20260801-001";
union withsource=TelemetryTable
(AppRequests
  | where TimeGenerated between (StartTime .. EndTime)
  | project TimeGenerated, OperationId, ParentId, Name, ResultCode, Success, Properties),
(AppDependencies
  | where TimeGenerated between (StartTime .. EndTime)
  | project TimeGenerated, OperationId, ParentId, Name, ResultCode, Success, Properties),
(AppTraces
  | where TimeGenerated between (StartTime .. EndTime)
  | project TimeGenerated, OperationId, ParentId, Name=Message, ResultCode="", Success=true, Properties),
(AppExceptions
  | where TimeGenerated between (StartTime .. EndTime)
  | project TimeGenerated, OperationId, ParentId, Name=OuterMessage, ResultCode="", Success=false, Properties)
| where tostring(Properties) has Canary
| order by TimeGenerated asc

Si le producteur et le consommateur sont présents avec deux OperationId différents, la rupture est probablement au passage du message. Si tout le worker manque, inspectez son SDK, sa chaîne de connexion Application Insights, son exporter OpenTelemetry et son workspace avant de modifier Service Bus. Si la donnée apparaît tard, mesurez l’ingestion avant de conclure.

Vérifier le contexte W3C au passage du message

Le contexte de trace W3C repose sur traceparent et, éventuellement, tracestate. Une instrumentation automatique peut les injecter et les extraire, mais un wrapper interne, un mapping vers un DTO, un bridge entre SDK ou une publication reconstruite à partir du seul body peut casser la chaîne.

Capturez les propriétés applicatives d’un message de canary dans un environnement contrôlé, sans journaliser le payload complet ni des données sensibles.

text service-bus-context-checklist.txt
Cote producteur
Une Activity ou un span est actif au moment de Send
Le format de propagation est W3C sur tous les services
L'instrumentation Service Bus n'est pas desactivee
Le wrapper conserve les application properties
Le span d'envoi porte namespace et nom d'entite attendus

Cote message
MessageId est stable et journalisable
traceparent est present et syntaxiquement valide
tracestate est conserve s'il est utilise
CorrelationId metier ne remplace pas le trace ID technique
Aucun retry ne regenere silencieusement un nouveau message logique

Cote consommateur
Le contexte est extrait avant de creer le span de traitement
Le span de traitement a le bon parent ou un lien explicite
Les logs executes dans le handler voient l'Activity active
Les dependances aval heritent de ce contexte

Ne faites pas du CorrelationId métier un substitut de traceparent. Le premier sert à retrouver une commande dans le domaine. Le second décrit la causalité technique entre spans. Les deux sont utiles et n’ont pas le même cycle de vie.

Reconstituer la cassure avec KQL

Une fois le canary trouvé, comparez les opérations observées autour de son MessageId. La requête suivante part des propriétés enrichies par l’application ; adaptez les noms de dimensions au schéma réellement émis.

kusto 02-rebuild-async-trace.kql
let StartTime = datetime(2026-08-01T06:00:00Z);
let EndTime = datetime(2026-08-01T07:00:00Z);
let Canary = "trace-canary-20260801-001";
let Telemetry = union
(AppRequests | project TimeGenerated, ItemType="request", OperationId, ParentId, Name, Success, Properties),
(AppDependencies | project TimeGenerated, ItemType="dependency", OperationId, ParentId, Name, Success, Properties),
(AppTraces | project TimeGenerated, ItemType="trace", OperationId, ParentId, Name=Message, Success=true, Properties),
(AppExceptions | project TimeGenerated, ItemType="exception", OperationId, ParentId, Name=OuterMessage, Success=false, Properties);
Telemetry
| where TimeGenerated between (StartTime .. EndTime)
| extend MessageId = tostring(Properties["messaging.message.id"]),
       Entity = tostring(Properties["messaging.destination.name"]),
       Role = tostring(Properties["cloud.role"])
| where MessageId == Canary or tostring(Properties) has Canary
| project TimeGenerated, Role, ItemType, Name, OperationId, ParentId, MessageId, Entity, Success
| order by TimeGenerated asc

Le premier point où OperationId change sans lien documenté localise la cassure. Vérifiez cependant les sémantiques de messaging : un traitement peut utiliser un parent direct ou un span lié selon le modèle de consommation. La preuve attendue n’est pas une forme graphique particulière, mais une causalité navigable entre publication, livraison, traitement et effets aval.

Contrôler le sampling avant de toucher au code

Deux services peuvent propager correctement le contexte et conserver des traces incomplètes si leurs politiques de sampling divergent. Comparez la configuration du producteur et du consommateur : ratio, sampling adaptatif, règles par type de span, exporter, processeur et ressource OpenTelemetry.

Pour un canary, appliquez temporairement une règle étroite qui conserve la trace de test à partir d’un attribut non sensible. N’augmentez pas le sampling global en production pour retrouver un seul incident : le coût et le volume masqueraient la cause, et la modification pourrait saturer la chaîne de télémétrie.

yaml canary-observability-plan.yml
canary:
message_id: trace-canary-20260801-001
business_side_effects: disabled
expected_segments:
  - api request
  - service bus send
  - service bus process
  - downstream dependency
temporary_controls:
  keep_canary_trace: true
  log_message_body: false
  expiry: 30m
stop_when:
  - payload data appears in telemetry
  - telemetry volume exceeds budget
  - worker processes an unexpected command
  - correlation still breaks after one controlled attempt

Choisir la correction la plus étroite

La correction dépend de la première preuve manquante. Gardez le changement réversible et limité à un composant.

text trace-repair-decision.txt
Corriger la propagation
traceparent manque dans les proprietes du message
Le producteur possede pourtant un span actif
Le wrapper de publication supprime les metadata

Corriger l'extraction
traceparent est present et valide
Le worker cree une nouvelle trace sans parent ni lien
Le contexte est extrait apres le debut du handler

Corriger la telemetrie
La correlation existe dans le runtime
Spans ou logs ne sont pas exportes
Le worker vise un autre workspace ou exporter

Corriger le sampling
Les OperationId concordent sur les elements conserves
Les trous suivent une politique de sampling differente
Le canary conserve confirme la chaine complete

Rollbacker
La cassure commence avec une mise a jour SDK ou instrumentation
La correction change le body ou le contrat metier du message
Le volume de telemetrie augmente sans restaurer la causalite
Les performances de publication ou consommation regressent

Évitez une correction qui copie manuellement des en-têtes à plusieurs endroits si le SDK et l’instrumentation utilisés savent déjà propager le contexte. Une duplication locale crée deux autorités et rend les upgrades suivants plus risqués.

Valider puis retirer le dispositif temporaire

Déployez d’abord sur un seul producteur ou consommateur. Envoyez un canary, puis vérifiez la trace de bout en bout, le temps de traitement, les retries, le volume de télémétrie et l’absence de données sensibles. Une trace complète qui double la latence du worker n’est pas une correction validée.

La validation de production doit confirmer trois choses : le nouveau message reste corrélé, les messages déjà en file sont encore traités, et le rollback restaure l’instrumentation précédente sans toucher aux données métier. Retirez ensuite la règle de sampling du canary et les logs temporaires.

Conclusion

Une trace cassée à la frontière Service Bus n’impose pas de redéployer toute la chaîne. Le runbook part d’un message sans effet métier, prouve chaque segment, contrôle traceparent, distingue propagation, export et sampling, puis modifie le premier composant fautif.

La décision finale est simple : conserver la correction uniquement si un canary relie requête, envoi, traitement et dépendances aval avec un coût maîtrisé. Sinon, rollbacker l’instrumentation, garder les identifiants du dossier de preuves et reprendre le diagnostic au dernier span confirmé.