Exemple File d'attente avec un automate
Sommaire |
Dans cet exemple nous allons mettre en oeuvre le design pattern file d'attente en utilisant :
- Une file d'attente stockée dans la base de données
- Un automate pour consommer les messages de cette file d'attente (consommateur)
- Un code script pour générer les messages (producteur)
- Un processus de traitement pour traiter les messages
Configuration de la file d'attente
La file d'attente est configurée par un objet TdbmMessageQueue du référentiel:
- Le nom de paramétrage de la file est DBQUEUE
- Le type de la file est DatabaseMQ ce qui indique qu'il s'agit d'une file gérée en base de données
- L'attribut QueueConnextionInfos indique le nom de la classe dans laquelle seront stockés les messages, il s'agit de la classe générique permettant de stocker n'importe quel message.
Code snippet du producteur
Le code générant un message dans la file est le suivant :
//Procedure TestQueueMessage; var msg:TdbmQueueMessage; idx:Integer; begin for idx:=1 to 1 do begin msg := TdbmQueueMessage.Create; msg.QueueName := 'DBQUEUE'; msg.AddParameter('uneChaine','some text'); msg.AddParameter('unEntier',1999); msg.BinaryContent.LoadFromFile('c:\image.jpg'); msg.Post; end; end;
Il peut être directement exécuté à partir du concepteur de modèle.
Notez que :
- Ce code ne connait pas la configuration de la file, il peut fonctionner avec n'importe quel type de file.
- Il ne fait pas référence à TdbmStoredQueueMessage (ce qui serait propre à la configuration de la file) mais à TdbmQueueMessage qui est un type non persistant générique représentant un message.
- Il écrit le message en base par un Post sur le message, c'est une action générique indépendante du type de la file.
- Le message contient deux paramètres et un contenu binaire
- Il ni a pas besoin de déclarer une transaction.
Code snippet du processus de traitement
La classe traitant les messages est la suivante :
unit TestSYFREWF; interface Type MyProcessus = Class(TitObject) public uneChaine: string; unEntier: integer; Procedure Execute; end; Implementation {MyProcessus} Procedure MyProcessus.Execute; //Procedure Execute; var aMsg:TdbmQueueMessage; idx:Integer; begin if Assigned(UserContext.TaskContext) then begin UserContext.TaskContext.AddMessage('MyProcessus.Execute'); if Assigned(UserContext.TaskContext.EventContext.receivedMsg) then begin aMsg := UserContext.TaskContext.EventContext.receivedMsg; UserContext.TaskContext.AddMessage('Has a message'); for idx:=0 to aMsg.Count-1 do begin UserContext.TaskContext.AddMessage(aMsg.DisplayStrings[idx]); end; // simulate job sleep(5000); end else UserContext.TaskContext.AddMessage('No message'); end else showMessage('not in a task'); end;; end.
Ce processus réalise :
- Vérifie qu'il s'exécute bien dans le contexte du tâche
- Trace dans les messages du contexte son exécution
- Récupère le message consommé (aMsg)
- Trace tous les paramètres du message dans messages du contexte
- Simule l'exécution d'un traitement.
Le processus sera exécuté par la tâche d'automate consommant les messages.
Configuration de la tâche d'automate
Evènement :
- L'évènement référence la file d'attente par son nom de paramétrage (DBQUEUE)
- L'intervalle de test est zéro (?)
Tâche :
Cet automate est configuré ainsi :
- L'évènement est de type File d'attente
- La tâche est de type traitement
- Les paramètres de la tâche référence le processus MyProcessus
- L'état suivant est -1
Exécution
Exécution du code producteur :
- On constate que ce code a créé un objet dans la classe TdbmStoredQueueMessage.
- Les paramètres du message sont stockés dans l'attribut Data
- Le contenu binaire est stocké dans l'attribut BinaryContent
Démarrage de l'automate :
On utilise une console SNMTP pour superviser l'exécution :
On constate que
- l'évènement DBQUEUE est déclenché.
- L'exécution de la tâche de traitement est réalisé.
La tâche de traitement génère une entrée dans le journal :
Tâche : Tâche de traitement Traiter un msg de DBQUEUE Société : Test SYFRE Workflow Utilisateur: syfre Base(s) : TestWorkFlowdup_7 Mode Soc. : Enchainer sur ces sociétés Société(s) : Début : 11/04/2013 09:39:19 Fin : 11/04/2013 09:39:24 Durée : 5 s Fichiers : 0 Statut : 0 OK MyProcessus.Execute Has a message MessageClassName="TStaticRegClass" MessageDatetime="11/04/2013" MessageUser="syfre" MessageOID="000000000000000000E30001A0FF0008" MessageID="166" Topic="WSMQCOPY" State="1" OriginalUniqueID="" idOTP="227" ObjectClassLabel="Classe message stocké d'une file d'attente" ObjectClassName="TDBMSTOREDQUEUEMESSAGE" oid="000000000000000000E30001A0FF0008" oiddbmQueue="" oidShare="" QueueName="WSMQCOPY" queueTopic="WSMQCOPY" ShareInfo="" ShareInstanceInfo="" ShareInstanceLevel="2" ShareInstanceRequestedLevel="-1" ShareLevel="0" UniqueID="166" UpdDate="11/04/2013" UpdStamp="00017D6100000022" UpdUser="syfre" uneChaine="some text" unEntier="1999"
Production de plusieurs messages
On peut modifier le code du producteur pour générer plusieurs messages :
//Procedure TestQueueMessage; var msg:TdbmQueueMessage; idx:Integer; begin for idx:=1 to 5 do begin msg := TdbmQueueMessage.Create; msg.QueueName := 'DBQUEUE'; msg.AddParameter('uneChaine','some text'); msg.AddParameter('unEntier',1999); msg.BinaryContent.LoadFromFile('c:\image.jpg'); msg.Post; end; end;
On constate les déclenchements de l'automate :
Chaque déclenchement est espacé d'environ 5 secondes qui correspondes au temps de traitement du processus.
Utilisation de plusieurs consommateurs
Il est possible de démarrer plusieurs services sur le même automate pour mettre en oeuvre plusieurs consommateurs :
[\SOFTWARE\Sage\Ligne 1000\Administration\IPC\SYFRE1] ipcMode=ipcTCP tcpPort=8091 section=SYFRE [\SOFTWARE\Sage\Ligne 1000\Administration\IPC\SYFRE2] ipcMode=ipcTCP tcpPort=8092 section=SYFRE [\SOFTWARE\Sage\Ligne 1000\Administration\Servers\SYFRE] Master Profil=dbMasterTahoe Server Societies=Test SYFRE Workflow Server Application=Test-SYFRE-WorkFlow Server User=syfre Server Password= Public Folder=C:\Mes documents\Server\ IPC Started=0 BP Started=0 Automate Name=SYFRE Automate Started=1 DEBUGGER Started=0 DEBUGGER Users=syfre,toto,titi SESSIONS profil=CONFIG_SESSION_1 SOAP Profil=CONFIG_SOAP_1 SNMP Profil=CONFIG_SNMP_1 SMTP Profil=CONFIG_SMTP_1 PROCESS Profil=CONFIG_PROCESS_1 --HTTP Profil=CONFIG_HTTP_INTERNAL
Une fois démarré chaque service exécute le même automate :
Lorsque l'on crée plusieurs messages dans la file d'attente :
On constate que les messages ont été consommés par les deux services.