Comparaison des versions

Légende

  • Ces lignes ont été ajoutées. Ce mot a été ajouté.
  • Ces lignes ont été supprimées. Ce mot a été supprimé.
  • La mise en forme a été modifiée.

...

Spécifications actuelles

Version 2.0

Structure d'un message

Un message RabbitMQ est composé de 2 parties : les propriétés et le payload.

Propriétés

Les propriétés permettent de caractériser un message et son traitement. Certaines sont obligatoires pour le fonctionnement de rabbitMQ alors que d'autres sont laissé à la libre appreciation des applications clientes. Voici les propriétés par défaut de RabbitMQ :

 

 

content-typeMIME content type.
content-encodingMIME content encoding.
delivery-modeNon-persistent (1) or persistent (2).
priorityMessage priority, 0 to 9.
correlation-idApplication correlation identifier.
reply-toAddress to reply to.
expirationMessage expiration specification.
message-idApplication message identifier.
timestampMessage timestamp.
typeMessage type name.
user-idCreating user id.
app-idCreating application id.
reservedReserved, must be empty.
headersMessage header field table.

 

Ci dessous sont définit les valeurs de ces paramètres et la signification donnée dans le SOA Gadz.org

content-type

Le Content-Type du payload. Gadz.org ne supporte pour l'instant que le type "application/json". Si la valeur est absente, le message est considéré comme du "application/json"

content-encoding

L'encodage du message. Gadz.org ne supporte pour l'instant que la valeur "deflate" mais la valeur "gzip" pourra être supporté pour réduire la charge sur le serveur RabbitMQ. En cas d'absence du paramètre, la valeur est par défaut à "deflate"

delivery-mode

Paramètre obligatoire de RabbitMQ, par défaut à 1 (Non-persistent). Ceci permet de savoir si le message doit être persisté sur le disque dur ou  non. Un message non persisté sera perdu en cas de coupure du serveur RabbitMQ

priority

Non utilisé par Gadz.org. Utilie uniquement pour les queues priorisées (doc)

message-id

Null par defaut. Gadz.org utilise un UUID (v1 ou v4, ceci n'a pas d'importance). C'est à l'applicaiton emmetrice de créer cet ID

correlation-id

Utilisé pour répondre à un message. Il référence l'ID du message de la requete dont son message est la réponse.

reply-to

Gadz.org utilise cette propriété pour définir l'exchange auquel la réponse doit être envoyé.

expiration

La durée de vie en milliseconde du message. Ceci permet d'éviter que certain message ne soit executer de manière trop différés ci ceux-ci peuvent provoquer des effet de bords. C'est à l’application envoyant le message de le définir.
Exemple : Limiter la durée de vie d'un message demande l'envoi d'un email de récupération de mot de passe à 3h . Si le message n'est pas traité dans les 3h, il s'auto détruit pour éviter d'envoyer un message hors contexte à l'utilisateur.
Avant d'utiliser se paramètre, veuillez lire la documentation rabbitMQ.

timestamp

Timestamp de création du message. C'est à l'application émettrice de l'ajouter (RabbitMQ ne l'ajoute pas par défaut).

type

Le type de message. Une des valeur suivante :  event , request , reply , log

user-id

User id utilisé pour se connecter à RabbitMQ. Null par défaut. Si l'expéditeur souhaite réveller son idéentité, user-id doit être égal au nom d'utilisateur RabbitMQ ou le message sera refusé

app-id

L'id de l'applicaiton emmetrice. Valeur a définir  par l'emmeteur

headers

Valeurs définies par l'application émettrices pouvant être utilisé par le consommateur

Voici les headers définis par Gadz.org :

HeadersObligatoireValeur si nullCommentaire
soa-versionOui1.0La version du SOA sur laquelle s'appuie l’émetteur. Ce numéro n’apparaît qu'à partir de la version 2
softfail-countNon0Le nombre de fois que ce message a été traité en softfail
client-libraryNonnullLe client utilisé par l'émetteur (ex: GorgService 5.3). Ceci facilite le debug et peut permettre d'adapter la réponse.
admin-idNonnullL'id de l'admin ayant déclenché cette action pour faciliter le debug e le suivit des action

Des headers supplémentaires peuvent être définis en fonction du type de message 

 Payload

Le payload contient les données devant être traitées par le consommateur du message. Il doit être du type défini par la propriété content-type

Types de messages

Événement (ou notification)

Un événement DOIT être envoyé à l'exchange d'événement (voir Topologie)

Un événement DOIT avoir pour type event 

Une requête DOIT avoir une clé de routage du type event.[identifiant_du_service_emmeteur].[resource].[evenement]. Par exemple event.gappsd.account.created

Les spécifications de l'attribut data du payload (voir Structure des messages) du message sont définies par le service émettant l'événement.

...

Une requête appel directement une fonction d'un service.

Un événement DOIT avoir pour type request 

Une requête PEUT attendre une réponse. Dans ce cas la requête DOIT contenir contenir le header la propriété reply_to_exchange ayant pour valeur le nom d'un exchange de réponse (voir Topologie).

Les spécifications de l'attribut data du payload (voir Structure des messages) du message sont définies par le service cible.

...

Un message de type "réponse" est émis en réponse à un message de type requête

Un événement DOIT avoir pour type reply 

Une réponse DOIT contenir le header request_event_uuid ayant la propriété correlation-id ayant pour valeur le uuid du message de la requête associée.

Une réponse DOIT être envoyée à un exchange de réponse (voir Topologie).

Les spécifications de l'attribut data du payload (voir Structure des messages) du message sont définies par le service émettant la réponse.

Une requête DOIT avoir une clé de routage du type reply.[identifiant_du_service_emmeteur].[resource_manipulée].[action]. Par exemple reply.gappsd.account.create.

Une réponse utilise également les headers suivant :

HeadersObligatoireValeur si nullCommentaire
statusOuiN/ALe statut de la réponse. Les code http sont utilisés (200 = succes, 4XX = erreur client, 5XX = erreur serveur
error-statusNonnullValeur admissible softfail , hardfail. Définit si l'erreur est permanenent ou temporaire. En cas d'erreur temporaire, l'émetteur de la requête
next-try-inNonnullEn cas de softfail - le délai en millisecondes du prochain essai prévu (a partir du timestamp de création du message). Si cet header n'est pas présent ou à "0" alors que le header "error-status" est présent, cela signifie que le service ne gère pas les softfails automatiquement.
error-nameNonnullEn cas d'erreur (statut >=400) - Un nom d'erreur permettant au client de traiter automatiquement l'erreur

Log

Un événement DOIT avoir pour type log 

Un message de type "log" permet de centraliser les logs liés aux messages et faciliter le debug.

Une réponse DOIT contenir la propriété correlation-id ayant pour valeur le uuid du message ayant généré le log

Un log DOIT être envoyée à l'exchange de log (voir Topologie).

Un log DOIT avoir une clé de routage identique au message ayant généré le log.

Structure des messages

Les messages doivent vérifier le schema JSON suivant :

Bloc de code
themeFadeToGrey
languagejavascript
titleSchema JSON des messages
collapsetrue
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "event_name": {
      "type": "string",
      "pattern": "^[_a-z]+((\\.)?[_a-z]+)*$",
      "description": "Event type. Must match the routing key"
    },
    "event_uuid": {
      "type": "string",
      "description": "The unique identifier of this message as UUID",
      "pattern": "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"
    },
    "event_creation_time": {
      "type": "string",
      "description": "Creation time in UTC ISO 8601 format",
      "pattern": "^([\\+-]?\\d{4}(?!\\d{2}\\b))((-?)((0[1-9]|1[0-2])(\\3([12]\\d|0[1-9]|3[01]))?|W([0-4]\\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\\d|[12]\\d{2}|3([0-5]\\d|6[1-6])))([T\\s]((([01]\\d|2[0-3])((:?)[0-5]\\d)?|24\\:?00)([\\.,]\\d+(?!:))?)?(\\17[0-5]\\d([\\.,]\\d+)?)?([zZ]|([\\+-])([01]\\d|2[0-3]):?([0-5]\\d)?)?)?)?$"
    },
    "event_sender_id": {
      "type": "string",
      "description": "Producer that sent the original message"
    }, 
    "data": {
      "type": "object",
      "description": "Data used to process this message"
    },
    "errors_count": {
      "type": "integer",
      "description": "Helper for counting errors"
    },
    "errors": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "error_type": {
            "enum": [  "debug", "info", "warning", "softerror", "harderror" ],
            "description": "Type of error."
          },
          "error_sender": {
            "type": "string",
            "description": "Consummer that sent this error"
          },
          "error_code":{
            "type":"string",
            "description": "Optionnal error code from the consummer"
          },
          "error_uuid":{
            "type":"string",
            "description": "The unique identifier of this error as UUID",
            "pattern": "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"
          },
          "error_message":{
            "type":"string",
            "description": "Error explanation"
          },          
          "timestamp": {
            "type": "string",
            "description": "Time of occuring error in UTC ISO 8601",
            "pattern": "^([\\+-]?\\d{4}(?!\\d{2}\\b))((-?)((0[1-9]|1[0-2])(\\3([12]\\d|0[1-9]|3[01]))?|W([0-4]\\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\\d|[12]\\d{2}|3([0-5]\\d|6[1-6])))([T\\s]((([01]\\d|2[0-3])((:?)[0-5]\\d)?|24\\:?00)([\\.,]\\d+(?!:))?)?(\\17[0-5]\\d([\\.,]\\d+)?)?([zZ]|([\\+-])([01]\\d|2[0-3]):?([0-5]\\d)?)?)?)?$"
          },
          "error_debug": {
            "type": "object",
            "description": "Complementary informations for debugging"
          }
        },
        "additionalProperties": false,
        "required": [
          "error_type",
          "error_sender",
          "timestamp",
          "error_uuid",
          "error_message"
        ]
      }
    }
  },
  "additionalProperties": false,
  "required": [
    "event_name",
    "event_uuid",
    "event_creation_time",
    "event_sender_id",
    "data"
  ]
}

Exemple de message :

...

languagejavascript
titleExemple de message

...

Le payload d'un message de log contient les données de debug

HeadersObligatoireValeur si nullCommentaire
levelOui1La valeur numérique du niveau (voir plus bas). L'utilisation du format numérique permet d'utiliser des exchanges de type "header" et ainsi trier les messages en fonciton de leur niveau.
next-try-innonnullEn cas de softfail
error-namenonnonUn nom d'erreur si il s'agit d'une erreur déjà identifiée

Niveaux de logs :

NiveauIdentifiantCommentaires
DEBUG0Des données de debug, ces logs ne sont pas voués à être utilisé en produciton de manière permanente
INFO1Logs permettant de suivre la progression du processus du service
WARNING2Logs avertissant d'une situation potentiellement dangereuse (utilisation d'une fonciton dépréciée ...)
SOFTFAIL3Logs avertissant d'un softfail.
HARDFAIL4Logs avertissant d'un hardfail

 

Types d'erreurs

Les messages sont séparés en 5 2 classes d'erreur

Info

Les termes "SofterrorSoftfail" et "HarderrorHardfail" sont tirés de la précédente version du manager Google Apps écrit en python par les X. https://github.com/vzanotti/gappsd

 

Debug

Non implémenté

Info

Non implémenté

Warning

Non implementé

...

Softfail

Une erreur temporaire empêche le traitement du message. Il s'agit d'une erreur due à l'environnement extérieur, indépendante du service consommateur. Le message est envoyé dans une queue de stockage pour être retraité plus tard automatiquement.

Exemples :

  • Problème réseau empéchant de se connecter à une API
  • Limite de vitesse d'utilisation d'une API atteinte

...

Hardfail

Une erreur empêche le traitement du message. Il s'agit d'une erreur du au message lui même. Le message ne peux et ne pourra jamais être traiter.

...

  • Json mal formaté
  • Données non valide (ex: pas d'email pour la demande de création d'un compte Google Apps existant déjà)

ChangeLog

v2.0

Utilisation des headers et des propriétés des messages plutot que du payload.

Passage de la V1 à la V2 : 

  • event_uuid  devient la propriété message-id
  • event_name est la routing key
  • event_creation_time  devient la propriété timestamp
  • event_sender_id  devient la propriété app-id
  • data devient le payload
  • Les logs ne sont plus contenues dans le message originel mais seulement relié via le correlation-id

v1.0

Première version