#Interopérabilité

0 Abonnés · 67 Publications

Dans le domaine de la santé, l'interopérabilité est la capacité de différents systèmes informatiques et applications logicielles à communiquer, à échanger des données et à utiliser les informations qui ont été échangées.

Article Iryna Mykhailova · Avr 29, 2024 12m read

Le défi du Lo-Code

Imaginons la scène.  Vous travaillez tranquillement au sein de Widgets Direct, le premier détaillant de Widgets et d'accessoires pour Widgets sur Internet.   Votre patron vous annonce une nouvelle désastreuse : certains clients ne sont peut-être pas satisfaits de leurs widgets et nous avons besoin d'une application d'assistance pour assurer le suivi de ces réclamations.   Pour rendre les choses plus intéressantes, il veut que cette application ait une très faible empreinte de code et vous demande de livrer une application en moins de 150 lignes de code à l'aide d'InterSystems IRIS.  Est-ce possible?

Avertissement : cet article présente la construction d'une application très basique et omet, par souci de concision, des éléments de détail tels que la Sécurité et la Gestion des erreurs.   Cette application ne doit être utilisée qu'à titre de référence ni pour une application de production.  Cet article utilise IRIS 2023.1 comme plate-forme de données, certaines fonctionnalités décrites ne sont pas disponibles dans les versions antérieures

Étape 1 – Définition d'un modèle de données

Nous commençons par définir un nouvel espace de noms propre - avec une base de données de codes et de données. Bien que tout soit regroupé dans une seule base de données, il est utile de diviser ces bases pour permettre l'actualisation des données.

Notre système d'assistance a besoin de 3 classes de base : un objet Ticket qui peut contenir des actions pour documenter les interactions entre un conseiller du personnel UserAccount et un contact client UserAccount.  Définissons ces classes avec quelques propriétés de base:

19 lignes de code – et nous avons notre modèle de données complet!  Nous avons défini 2 classes comme Persistent afin qu'elles puissent être sauvegardées dans la base de données, et nous héritons également de %JSON.Adapter, ce qui nous permet d'importer et d'exporter très facilement nos objets au format JSON.  En guise de test, nous configurons notre premier utilisateur dans Terminal, nous le sauvegardons et nous vérifions que l'application JSONExport fonctionne correctement

Tout cela semble bon.  Le patron nous a laissé un fichier csv avec une liste d'employés et de clients.   Nous pourrions écrire un code pour analyser ce fichier et le charger, mais y a-t-il un moyen plus simple?

Étape 2 – TÉLÉCHARGEMENT DES DONNÉES

InterSystems IRIS fournit une instruction de chargement de données (LOAD DATA) simple à utiliser en SQL qui permet de télécharger facilement des données à partir d'un fichier CSV, y compris les options permettant d'analyser les en-têtes et de renommer les champs.  Utilisons-la pour télécharger notre table d'utilisateurs:

Nous pouvons utiliser les étiquettes d'en-tête pour extraire ces données et les télécharger dans la base de données de la manière suivante:

Les 300 lignes ont été importées en une seule commande.   Les 4 lignes supplémentaires de code portent notre compte courant à 23 lignes de code écrites.   Nous pouvons rapidement vérifier que ces enregistrements sont corrects avec une sélection SQL de base

Nous avons maintenant nos données de départ, construisons donc quelques API de base pour permettre à un front-end d'être connecté.  Nous construirons notre API comme un service REST qui sert et accepte JSON.

Étape 3 – Création d'une API REST

InterSystems IRIS fournit un support REST natif par le biais de l'héritage de la classe %CSP.REST, nous allons donc créer une classe REST.Dispatch et hériter de %CSP.REST.   Cette classe est composée de deux sections: une UrlMap XData qui associe les URL et les Verbes aux méthodes, et les méthodes qui sont appelées par ces Urls.

Notre Produit minimum viable nécessite 4 opérations: la récupération de la liste des utilisateurs pour le personnel ou les clients, la récupération des derniers tickets collectés, la récupération d'un ticket unique par son numéro d'identification, et enfin la création d'un nouveau ticket.   Nous définissons nos verbes, et puis les méthodes.

GetUserList est un Curseur de base SQL intégré qui fournit les données directement en JSON.  Nous pouvons alors analyser ces données avec la fonctionnalité JSON native, les placer dans un tableau JSON et les servir en tant que corps de la réponse.  Nous passons la variable "staff" de l'URL directement à la requête pour modifier le contexte des données.

TicketSummary est presque identique, mais la requête accède alors à la table des tickets

TicketSummary est le service le plus simple.  Nous ouvrons l'objet par ID, et écrivons le %JSONExport intégré à la sortie.  Si l'objet ne se charge pas, alors nous écrivons un paquet d'erreurs

Enfin, notre méthode d'UploadTicket est la plus complexe. Nous devons lire le payload de l'objet de la requête, l'analyser en JSON, puis l'appliquer à une nouvelle instance de Ticket en utilisant %JSONImport.  Nous définissons également l'OpenDate et l'OpenTime à partir de l'heure actuelle, au lieu de les attendre en entrée.  Après une sauvegarde réussie, nous renvoyons la représentation JSON de l'objet, ou si l'objet ne se télécharge pas, nous renvoyons une erreur.

Avec ces services, nous ajoutons 60 lignes de code supplémentaires à notre total.  Nous atteignons maintenant un total de 89 lignes de code pour cette application

Nous devons maintenant créer une application Web sous Sécurité>Applications.  Celle-ci doit être définie comme une application de type REST, et le NOMCLASSE (Classname) doit être défini comme la classe de répartition (Dispatch) que nous venons de créer (Remarque: vous devrez accorder un rôle de sécurité approprié à cette application afin qu'elle puisse accéder au code et aux données).  Après avoir sauvegardé, les services REST peuvent maintenant être appelés à partir de l'URL que vous avez définie

Nous pouvons appeler l'UserList pour vérifier

Nous sommes maintenant prêts à créer des données.  Utilisons notre client REST pour envoyer un payload au service de création de tickets.  Nous fournissons un mot-clé, une description, un conseiller (Advisor) et un contact (Contact), et nous recevons en retour le fichier JSON du ticket que nous avons créé, y compris l'OpenDate et le TicketId

Nous avons maintenant notre Produit minimum viable.  En utilisant un constructeur de formulaire frontal de notre choix, nous pouvons maintenant envoyer et recevoir des informations sur les tickets via nos services REST.

Étape 4 – Exigences d'interopérabilité

Vous avez maintenant construit une application de ticketing de base en seulement 89 lignes de code écrites.   Votre patron doit être impressionné?   Oui, mais il a de mauvaises nouvelles.  Vous avez oublié une exigence.   Widgets Direct a un contrat spécial avec les régions francophones et tous les billets rédigés en français doivent être envoyés à Mme Bettie Francis pour un premier examen.   Heureusement, vous avez un collègue qui a suivi l'excellent article de Robert Luman "Sur la prise en charge du langage naturel par Python" ("Python Natural Language Support") et qui a créé un service REST capable d'accepter un échantillon de texte et d'en identifier la langue.   Pouvons-nous utiliser l'Interopérabilité d'InterSystems IRIS pour appeler ce service et mettre automatiquement à jour le conseiller de Mme Francis lorsque le texte est en français?

Nous devons commencer par la création de Classes de messages afin d'avoir un moyen d'envoyer et de recevoir nos demandes.  Nous avons besoin d'une requête qui contiendra l'identifiant du ticket et le texte de l'échantillon, et d'une réponse qui renverra le Code de la langue et la Description. Ceux-ci hériteront d' Ens. Request et d'Ens. Response

6 autres lignes de code écrites nous permettent d'atteindre 95 LOC.  Nous devons maintenant créer notre opération, qui enverra la requête au service de votre collègue et récupérera la réponse.  Nous définissons une opération Outbound, avec des propriétés pour le serveur et l'URL, et nous les exposons à la configuration de l'utilisateur en les incluant dans le paramètre SETTINGS.   Cela nous permettra de mettre facilement à jour la requête si le chemin d'accès au serveur change.   Nous créons une méthode d'aide pour configurer une requête HTTPRequest, puis nous l'utilisons pour appeler le service et remplir notre réponse

27 lignes de code supplémentaires nous amènent à plus de 100, nous avons maintenant 122 lignes écrites.   Nous devons maintenant configurer cette classe dans notre production Ensemble.  Nous devons maintenant configurer cette classe dans notre production Ensemble. Accédez à la configuration de la production sous Interopérabilité, et cliquez sur Ajouter (Add) sous l'En-tête Opérations (Operations Header).  Configurez votre opération avec le nom de la classe et un nom d'affichage

Nous pouvons ensuite cliquer dessus pour accéder aux paramètres (Settings), entrer le nom du serveur et l'URL et activer l'Opération. 

Nous avons maintenant besoin d'une deuxième opération qui prend l'identifiant d'un ticket et associe le conseiller à l'identifiant d'un compte d'utilisateur fourni.  Nous avons besoin à la fois d'un message et d'une classe d'opération, mais dans ce cas, nous ne renverrons pas de réponse, l'opération exécutera la tâche sans feedback

Les 12 lignes de code supplémentaires nous amènent à 134 lignes écrites.  Nous pouvons ajouter cette Opération à la Production de la même manière que nous avons ajouté le Service linguistique (Language Service), mais dans ce cas, nous n'avons pas de configuration à définir.

Nous avons ensuite besoin d'un routeur capable d'appeler le service, d'évaluer la réponse et, éventuellement, d'appeler l'Opération du conseiller français (French Advisor Operation).  Nous allons vers Interoperability>Build>BusinessProcess et accédons à l'outil de création de règles visuelles.  Nous définissons d'abord nos contextes pour la requête (Request) et la réponse (Response) et nous ajoutons un élément d'appel (Call).  Nous définissons nos entrées et nos sorties sur les classes de messages que nous avons créées, puis nous mappons les entrées à l'aide du générateur de requêtes.  Assurez-vous que l'option "Asynchrone" (Asynchronous) n'est pas cochée, car nous voulons attendre la réponse avant de continuer.

Nous ajoutons ensuite un élément "Si" (If) pour évaluer le code de langue renvoyé.  S'il s'agit de "fr", nous voulons faire appel à l'opération de FrenchAdvisor

Mme Francis est l'utilisateur ID 11, nous configurons donc notre objet d'appel (Call object) pour qu'il fournisse notre message AdvisorUpdate au service FrenchAdvisor, et nous utilisons le constructeur de requêtes pour transmettre le TicketID et une valeur fixe de 11 au paramètre Advisor

Nous pouvons maintenant l'ajouter à la Production en cliquant sur Ajouter (Add) sous l'en-tête Processus, en sélectionnant la classe et en lui donnant un nom d'affichage "FrenchRouter". 

Nous avons maintenant notre routage en place. Nous avons juste besoin d'un service pour rechercher les nouveaux tickets et les envoyer au routeur pour traitement.  Nous définissons une classe de service basée sur un adaptateur SQL de la manière suivante (en ajoutant 8 lignes de code supplémentaires à notre compte):

Nous l'ajoutons ensuite à notre production comme nous l'avons fait avec les objets Operation et Process.  Nous devons configurer l'adaptateur SQL.   Nous fournissons les détails de connexion via un DSN de type ODBC à la base de données locale, ainsi qu'une requête SQL de base que le Service utilisera pour interroger les tickets sur un minuteur défini dans le paramètre d'intervalle d'appel CallInterval.   Cette requête est associée au paramètre Key Field Name qui définit la clé unique de la requête et empêche le renvoi d'enregistrements déjà envoyés

Avec ceci en place, nous avons maintenant une production complète qui va scanner les nouveaux tickets, passer le texte à un service externe pour analyser la langue, et éventuellement réinitialiser le conseiller en fonction de la réponse.  Essayons cela!  Nous commençons par envoyer une requête en anglais, qui nous est retournée sous la forme TicketId 70.  Nous attendons une seconde, et accédons à cet enregistrement via le service GetTicket REST, ici le conseiller est inchangé par rapport à la requête originale

Répétons l'opération avec le texte en français (French Text)

Lorsque nous réclamons le ticket 71, notre conseiller a été changé en Mme Francis, comme nous nous y attendions! Nous pouvons le vérifier dans l'Interoperability en localisant le message dans Visual Trace, et en vérifiant que les Opérations ont été appelées comme prévu.

Nous en sommes maintenant à 142 lignes de code écrites, et nous avons une application d'InterSystems IRIS qui persiste les données, les a chargées en utilisant LOAD DATA, fournit une API REST de base pour la visualisation et l'édition des données, et un moteur d'intégration avancé fournissant un Support de décision basé sur des appels à un service REST externe.  Assurément, personne ne peut demander mieux?

Étape 5 – En savoir plus: Analyse

Votre application est un succès retentissant et les données affluent.   L'accès à ces données précieuses nécessite une certaine expertise, et la direction de Widgets Direct souhaite obtenir des informations.  Est-il possible de fournir un accès interactif aux données?

Grâce à InterSystems IRIS Analytics, nous pouvons fournir un accès facile et rapide à des outils de manipulation de données évolués.   Nous devons d'abord activer le support Analytics sur notre application web interne: 

Cela nous permet d'utiliser la section Analytics par rapport à notre Espace de noms.  Commencez par ouvrir Analytics>Architect.  Sélectionnez Nouveau (New) et remplissez le formulaire pour créer un Cube d'analyse pour la classe de tickets. 

Ensuite, nous pouvons configurer nos dimensions et une liste déroulante Drilldown à l'aide du constructeur Visual Builder.   Cette vue est accessible par glisser-déposer.  Une liste peut également être créée à l'aide d'un constructeur visuel simple, afin de personnaliser ce que l'utilisateur voit lorsqu'il interroge un point de données

Une fois la configuration de base établie, nous pouvons Sauvegarder, Compiler et Construire le Cube.  Cela permettra de configurer tous les indices et d'activer le Cube pour l'analyse dans le logiciel Analyzer.   Ouvrez l'Analyzer pour commencer à jouer avec les données.   Dans l'exemple présenté, nous pouvons facilement comparer les conseillers par rapport à une hiérarchie d'années et de trimestres filtrés par le contact en question.   Une fois que vous avez cliqué sur une cellule, vous pouvez appuyer sur l'icône des jumelles pour appeler la liste Drilldown que vous avez créée en vue d'une analyse et d'une exportation plus approfondies

Conclusion

Avec seulement 142 lignes de code, nous disposons d'une application BackEnd moderne, simple mais fonctionnelle, avec des outils permettant la communication inter-applications et l'analyse avancée.   Il s'agit d'une mise en œuvre simplifiée à l'extrême qui ne doit être utilisée que comme exemple des éléments de base nécessaires à la construction d'une application de base de données dans IRIS.  Comme il a été mentionné au début de l'article, ce code n'est pas prêt pour la production et, dans le cadre d'une utilisation réelle, les développeurs doivent se référer à la documentation et aux meilleures pratiques d'InterSystems IRIS pour s'assurer que leur code est robuste, sécurisé et évolutif (aucune de ces caractéristiques ne s'applique à cette base de code).  Bon codage!

1
0 99
Article Pierre LaFay · Avr 9, 2024 4m read

Introduction

Il existe une option d'assistant de procédure de liaison dans le portail de gestion (Système > SQL > Assistants > Procédure de liaison) avec laquelle j'ai eu des problèmes de fiabilité, j'ai donc décidé d'utiliser cette solution à la place.

Problème

0
0 77
Article Pierre LaFay · Avr 9, 2024 5m read

J'ai récemment eu besoin de surveiller depuis HealthConnect les enregistrements présents dans une base de données NoSQL dans le Cloud, plus précisément Cloud Firestore, déployé dans Firebase. D'un coup d'œil rapide, j'ai pu voir à quel point il serait facile de créer un adaptateur ad-hoc pour établir la connexion en tirant parti des capacités d'Embedded Python, et je me suis donc mis au travail.

Préparation de l'environnement

0
0 75
Article Pierre LaFay · Mars 21, 2024 1m read

InterSystems FAQ rubric

Record maps sont utilisés pour faire correspondre efficacement des fichiers contenant des enregistrements délimités ou des enregistrements de largeur fixe aux classes de messages utilisées par la fonction d'interopérabilité, et pour faire correspondre des fichiers de classes de messages de la fonction d'interopérabilité à des fichiers texte.

Le définitions de correspondace peuvent être créés à l'aide du portail de gestion, et nous fournissons également un assistant d'enregistrement CSV qui vous permet de définir tout en lisant un fichier CSV.

0
0 55
Article Sylvain Guilbaud · Fév 23, 2024 5m read

Dans cet article, je partagerai le thème que nous avons présenté lors du Global Summit 2023, dans la salle Tech Exchange. Moi et @Rochael Ribeiro

Lors de cette présentation, nous abordons les sujets suivants :

  • Outils Open Exchange pour des API rapides
  • Spécification de l'Open API
  • Développement d'API traditionnel ou Fast
  • API composite (interopérabilité)
  • Approche Spec-First ou Api-First
  • Gouvernance et surveillance des API
  • Démo (vidéo)

Outils Exchange ouverts pour des API Fast

0
2 113
Article Sylvain Guilbaud · Fév 12, 2024 10m read

La nouveauté de la version 2023.3 (d'InterSystems IRIS for Health) est une fonctionnalité permettant d'effectuer une validation basée sur le profil FHIR.

 (*)

Dans cet article, je vais fournir un aperçu de base de cette fonctionnalité.

Si FHIR est important pour vous, vous devriez absolument essayer cette nouvelle fonctionnalité, alors poursuivez votre lecture.

0
0 110
Article Pierre LaFay · Fév 7, 2024 8m read

Introduction

Il n'y a pas si longtemps, j'ai vu l'idée de using Python Class Definition Syntax to create IRIS classes

sur le portail d'idées d'InterSystems. Elle a attiré mon attention car l'intégration d'un maximum de syntaxes donne de la visibilité aux produits d'InterSystems pour les programmeurs ayant de l'expérience dans de nombreux langages.

0
0 65
Article Guillaume Rongier · Jan 17, 2024 7m read

Bienvenue dans le prochain chapitre de ma série CI/CD, où nous discutons des approches possibles vers le développement de logiciels avec les technologies InterSystems et GitLab. Aujourd'hui, nous reprenons la discussion sur l'interopérabilité, et plus particulièrement sur le suivi de vos déploiements d'interopérabilité. Si vous ne l'avez pas encore fait, configurez Alerte pour toutes vos productions d'interopérabilité afin de recevoir des alertes sur les erreurs et l'état de la production dans son ensemble.

Le paramètre de délais d'inactivité Inactivity Timeout est commun pour tous les hôtes métier d'interopérabilité (Interoperability Business Hosts). Un hôte métier possède le statut Inactif lorsqu'il n'a reçu aucun message pendant le nombre de secondes spécifié dans le champ de délai d'inactivité " Inactivity Timeout ". La fonction de surveillance de la production " Monitor Service " examine périodiquement l'état des services et des opérations métier au sein de la production et marque les éléments comme étant inactifs s'ils n'ont rien fait pendant le délai d'inactivité. La valeur par défaut est 0 (zéro). Si ce paramètre est 0, l'hôte métier ne sera jamais marqué comme Inactif, quelle que soit la durée de son inactivité.

Ce paramètre est extrêmement utile, car il génère des alertes qui, associées aux alertes configurées, permettent de signaler les problèmes de production en temps réel. Le fait que l'élément "Business Host" soit inactif signifie qu'il peut y avoir des problèmes de production, d'intégration ou de connectivité réseau qui nécessitent d'être examinés. Cependant, le Business Host ne peut avoir qu'un seul paramètre constant pour le délai d'inactivité, ce qui peut générer des alertes inutiles pendant les périodes connues de faible trafic : nuits, week-ends, vacances, etc. Dans cet article, je décrirai plusieurs approches pour la mise en œuvre dynamique des délais d'inactivité (Inactivity Timeout). Bien que je fournisse un exemple fonctionnel (qui fonctionne actuellement en production pour l'un de nos clients), cet article est plutôt un guide pour votre propre mise en œuvre dynamique des délais d'inactivité, donc ne considérez pas la solution proposée comme la seule alternative.

Idée

Le moteur d'interopérabilité maintient une globale spéciale HostMonitor, qui contient chaque Business Host sous forme d'indice, et l'horodatage de la dernière activité sous forme de valeur. Au lieu d'utiliser le délai d'inactivité, nous allons surveiller nous-mêmes cette globale et générer des alertes en fonction de l'état de HostMonitor. HostMonitor est maintenue que soit la valeur du délai d'inactivité définie - elle est toujours activée.

Mise en œuvre

Pour commencer, voyons comment nous pouvons itérer la globale HostMonitor :

Set tHost=""
For {
Set tHost=$$$OrderHostMonitor(tHost)
Quit:""=tHost
Set lastActivity = $$$GetHostMonitor(tHost,$$$eMonitorLastActivity)
}

Pour créer notre Monitor Service, il nous faut effectuer les vérifications suivantes pour chaque Business Host :

  1. Décidez si le Business Host est concerné par notre configuration dynamique des délais d'inactivité (par exemple, les interfaces hl7 à fort trafic peuvent fonctionner avec le délai d'inactivité habituel).
  2. Si le Business Host se trouve dans le champ d'action, nous devons calculer le temps écoulé depuis la dernière activité.
  3. En fonction du temps d'inactivité et d'un certain nombre de conditions (heure du jour/de la nuit, jour de la semaine), nous devons décider si nous voulons envoyer une alerte.
  4. Si nous voulons envoyer un enregistrement d'alerte, nous devons enregistrer l'heure de la Dernière activité (Last Activity) afin de ne pas envoyer la même alerte deux fois.

Notre code se présente comme suit :

Set tHost=""
For { 
  Set tHost=$$$OrderHostMonitor(tHost) 
  Quit:""=tHost
  Continue:'..InScope(tHost)
  Set lastActivity = $$$GetHostMonitor(tHost,$$$eMonitorLastActivity)
  Set tDiff = $$$timeDiff($$$timeUTC, lastActivity)
  Set tTimeout = ..GetTimeout(tDayTimeout)
  If (tDiff > tTimeout) && ((lastActivityReported="") || ($system.SQL.DATEDIFF("s",lastActivityReported,lastActivity)>0)) {
    Set tText = $$$FormatText("InactivityTimeoutAlert: Inactivity timeout of '%1' seconds exceeded for host '%2'", +$fn(tDiff,,0), tHost)
    Do ..SendAlert(##class(Ens.AlertRequest).%New($LB(tHost, tText)))
    Set $$$EnsJobLocal("LastActivity", tHost) = lastActivity
  } 
}

Vous devez implémenter les méthodes InScope et GetTimeout contenant votre logique personnalisée, et vous êtes prêt à démarrer. Dans mon exemple, il y a des délais de jour (Day Timeouts, qui peuvent être différents pour chaque Business Host, mais avec une valeur par défaut) et des délais de nuit (Night Timeouts, qui sont les mêmes pour tous les Business Hosts enregistrés), de sorte que l'utilisateur doit fournir les paramètres suivants :

  • Champs d'application : Liste des noms (ou parties de noms) de Business Host associés à leur valeur DayTimeout personnalisée, une par ligne. Seuls les Business Hosts qui se trouve dans le champ d'action (qui remplissent la condition $find(host, scope) pour au moins un champ d'action) seront suivis. Laisser ce champ vide pour surveiller tous les Business Hosts. Exemple: OperationA=120
  • DayStart : Nombre de secondes depuis 00:00:00, point de départ d'une journée. Il doit être inférieur à DayEnd. Par exemple, 06:00:00 AM est 6*3600 = 21600
  • DayEnd: Nombre de secondes depuis 00:00:00, point de fin d'une journée. Il doit être supérieur à DayStart. Par exemple 08:00:00 du soir est (12+8)*3600 = 72000
  • DayTimeout : Valeur du délai d'attente par défaut en secondes pour le déclenchement d'alertes pendant la journée.
  • NightTimeout : Valeur du délai d'attente par défaut en secondes pour le déclenchement d'alertes pendant la nuit.
  • WeekendDays: Jours de la semaine considérés comme week-end. Séparés par des virgules. Pour le week-end, NightTimeout s'applique 24 heures par jour. Exemple : 1,7 Vérifiez la valeur DayOfWeek de la date en exécutant : $SYSTEM.SQL.Functions.DAYOFWEEK(date-expression). Par défaut, les valeurs renvoyées représentent les jours suivants : 1 - dimanche, 2 - lundi, 3 - mardi, 4 - mercredi, 5 - jeudi, 6 - vendredi, 7 - samedi.

Voici le code complet, mais je ne pense pas qu'il y ait quelque chose d'intéressant là-dedans. Il implémente simplement les méthodes InScope et GetTimeout. Vous pouvez utiliser d'autres critères et adapter les méthodes InScope et GetTimeout si nécessaire.

Problèmes

Il y a deux problèmes à aborder:

  • Pas d'icône jaune pour les Business Hosts inactifs (puisque la valeur du paramètre InactivityTimeout de l'hôte est nulle).
  • Paramètres hors hôte - les développeurs doivent se rappeler de mettre à jour ce service de surveillance personnalisé chaque fois qu'ils ajoutent un nouvel Business Host et qu'ils souhaitent utiliser une implémentation dynamique de délais d'inactivité.

Alternatives

J'ai exploré toutes ces approches avant de mettre en œuvre la solution ci-dessus :

  1. Créer le Business Service qui modifie les paramètres InactivityTimeout lorsque le jour ou la nuit commence. Au départ, j'ai essayé de suivre cette voie mais j'ai rencontré un certain nombre de problèmes, principalement l'obligation de redémarrer tous les Business Hosts concernés à chaque fois que nous modifions le paramètre InactivityTimeout.
  2. Ajouter de règles dans le processeur d'alertes personnalisé (Custom Alert Processor) qui, au lieu d'envoyer l'alerte, la suppriment si c'est le délai nocturne InactivityTimeout. Mais une alerte d'inactivité provenant de Ens.MonitorServoce met à jour la valeur LastActivity, donc je ne vois pas de moyen, à partir d'un Custom Alert Processor, d'obtenir un "vrai" horodatage de dernière activité (à part interroger Ens.MessageHeader, je suppose ?). Et si c'est " nuit " - retourner l'état de l'hôte à OK, si ce n'est pas encore " InactivityTimeout " nocturne, et supprimer l'alerte.
  3. L'extension de Ens.MonitorService ne semble pas possible sauf pour le callback OnMonitor, mais cela sert un autre but.

Conclusion

Toujours configurer [alerte] https://docs.intersystems.com/iris20233/csp/docbook/Doc.View.cls?KEY=ECONFIG_alerts) pour toutes vos productions d'interopérabilité afin de recevoir des alertes sur les erreurs et l'état de la production dans son ensemble. Si une configuration statique de délai d'inactivité n'est pas suffisante, vous pouvez facilement créer une implémentation dynamique.

Liens

0
0 67
Article Pierre LaFay · Jan 9, 2024 3m read

Bonjour la communauté,

Lors de l'utilisation d'un Business Service de type SQL, il peut arriver que nous ayons besoin de rejouer certaines lignes de la table source.

Prenons comme exemple le Service Métier "from customer SQL" utilisant la classe générique

EnsLib.SQL.Service.GenericService

Différents cas se présentent, selon les paramètres utilisés sur ce Business Service

Premier cas :

Si le Business Service utilise uniquement KeyFieldName

0
0 40
Article Sylvain Guilbaud · Jan 8, 2024 3m read

Bonjour La Communauté,

en utilisant un Business Service de type SQL, il peut arriver que nous ayons besoin de rejouer certaines lignes de la table source.

Prenons comme exemple le Business Service "from customer SQL"  utilisant la classe générique EnsLib.SQL.Service.GenericService

Différents cas se présentent, en fonction des paramétres utilisés sur ce Business Service.

Premier cas :

Si le Business Service utilise uniquement un champ clé (KeyFieldName)

0
0 51
Article Guillaume Rongier · Jan 8, 2024 14m read

Bienvenue dans le prochain chapitre de ma série CI/CD, où nous discutons des approches possibles vers le développement de logiciels avec les technologies InterSystems et GitLab.

Aujourd'hui, parlons d'interopérabilité.

Problème

Lorsque vous avez une production d'interopérabilité active, vous avez deux flux de processus distincts : une production active qui traite les messages et un flux de processus CI/CD qui met à jour le code, la configuration de la production et les paramètres par défaut du système.

De toute évidence, le processus CI/CD affecte l'interopérabilité. Mais il y a des questions :

  • Que se passe-t-il exactement lors d'une mise à jour ?
  • Que devons-nous faire pour minimiser ou éliminer les temps d'arrêt de la production lors d'une mise à jour ?

Terminologie

  • Business Host (BH) - un élément configurable de la production d'interopérabilité : Service métier (BS), Processus métier (BP, BPL) ou Opération métier (BO).
  • Business Host Job (Job) - Tâche InterSystems IRIS qui exécute le code du Business Host et qui est gérée par la production d'interopérabilité.
  • Production : ensemble interconnecté de serveurs d'entreprise (Hôte métier).
  • System Default Settings (Paramètres par défaut du système) (SDS) - valeurs spécifiques à l'environnement dans lequel InterSystems IRIS est installé.
  • Message actif - demande en cours de traitement par une tâche Business Host Job. Une tâche Business Host Job peut avoir un maximum d'un Message actif. Une tâche Business Host Job qui n'a pas de message actif est inactif.

Qu'est-ce qui se passe?

Commençons par le cycle de vie de la production.

Démarrage de la production

Tout d'abord, la production peut être démarrée. Une seule production par espace de noms peut être lancée simultanément, et en général (à moins que vous ne sachiez vraiment ce que vous faites et pourquoi vous le faites), vous ne devrez lancer qu'une seule production par espace de noms, jamais. Il n'est pas recommandé de passer d'un espace de noms à l'autre entre deux ou plusieurs productions différentes. Le démarrage de la production démarre tous les Business Hosts activés définis dans la production. Le fait que certains Business Hosts ne démarrent pas n'affecte pas le démarrage de la production.

Conseils:

  • Démarrez la production à partir du portail de gestion du système ou en appelant : ##class(Ens.Director).StartProduction("ProductionName")
  • Exécutez un code arbitraire au démarrage de la production (avant qu'un Job Business Host ne soit démarré) en implémentant une méthode OnStart.
  • Le démarrage de la production est un événement contrôlable. Vous pouvez toujours voir qui et quand a fait cela dans le journal d'audit.

Mise à Jour de la production

Après le démarrage de la production, l'outil Ens.Director surveille en permanence la production en cours. Il existe deux états de production : état cible, défini dans la classe de production et les paramètres par défaut du système ; et état en cours d'exécution - les tâches en cours d'exécution avec les paramètres appliqués lors de la création des tâches. Si l'état souhaité et l'état actuel sont identiques, tout va bien, mais la production peut (et doit) être mise à jour s'il y a une différence. Habituellement, vous voyez cela sous la forme d'un bouton rouge "Mettre à jour" sur la page Configuration de la production dans le Portail de gestion du système.

La mise à jour de la production signifie une tentative pour que l'état de production actuel corresponde à l'état de production cible.

Lorsque vous exécutez ##class(Ens.Director).UpdateProduction(timeout=10, force=0) pour mettre à jour la production, il effectue les opérations suivantes pour chaque Business Host :

  1. Comparez les réglages actifs aux réglages de production/SDS/classe.
  2. Uniquement si (1) révèle une incohérence, le Business Host est marqué comme étant obsolète et nécessitant une mise à jour.

Après avoir exécuté cette opération pour chaque Business Host, UpdateProduction construit l'ensemble des changements :

  • Business Hosts à arrêter
  • Business Hosts à démarrer
  • Paramètres de production à mettre à jour

Ensuite, il les applique.

De cette manière, la "mise à jour" des paramètres sans rien changer n'entraîne aucune interruption de la production.

Conseils:

  • Mettre à jour la production à partir du portail de gestion du système ou en appelant : ##class(Ens.Director).UpdateProduction(timeout=10, force=0)
  • Le délai de mise à jour par défaut du portail de gestion du système est de 10 secondes. Si vous savez que le traitement de vos messages prend plus de temps, appelez Ens.Director:UpdateProduction avec un délai plus long.
  • Le délai de mise à jour est un paramètre de production, et vous pouvez le modifier pour une valeur plus importante. Ce paramètre s'applique au portail de gestion du système.

Mise à jour du code

UpdateProduction NE MET PAS A JOUR les BHs dont le code est obsolète. C'est un comportement orienté vers la sécurité, mais si vous voulez mettre à jour automatiquement tous les BHs en cours d'exécution lorsque le code sous-jacent change, suivez les étapes suivantes :

First, load and compile like this:

do $system.OBJ.LoadDir(dir, "", .err, 1, .load)
do $system.OBJ.CompileList(load, "curk", .errCompile, .listCompiled)

Maintenant, listCompiled contiendrait tous les éléments qui ont été compilés (utilisez git diffs pour minimiser l'ensemble des éléments importés) à cause du marqueur u. Utilisez cette listCompiled pour obtenir un $lb de toutes les classes qui ont été compilées :

set classList = ""
set class = $o(listCompiled(""))
while class'="" { 
  set classList = classList _ $lb($p(class, ".", 1, *-1))
  set class=$o(listCompiled(class))
}

Et ensuite, calculer une liste de BHs qui nécessitent un redémarrage :

SELECT %DLIST(Name) bhList
FROM Ens_Config.Item 
WHERE 1=1
  AND Enabled = 1
  AND Production = :production
  AND ClassName %INLIST :classList

Enfin, après avoir obtenu bhList, arrêtez et démarrez les hôtes affectés :

for stop = 1, 0 {
  for i=1:1:$ll(bhList) {
    set host = $lg(bhList, i)
    set sc = ##class(Ens.Director).TempStopConfigItem(host, stop, 0)
  }
  set sc = ##class(Ens.Director).UpdateProduction()
}

Arrêt de production

Les productions peuvent être arrêtées, ce qui implique d'envoyer une demande à tous les Jobs Business Host pour qu'ils s'arrêtent (en toute sécurité, une fois qu'ils ont terminé leurs messages actifs, le cas échéant).

Conseils:

  • Arrêtez la production à partir du portail de gestion du système ou en appelant : ##class(Ens.Director).StopProduction(timeout=10, force=0)
  • Le délai d'arrêt par défaut du portail de gestion du système est de 120 secondes. Si vous savez que le traitement de vos messages prend plus de temps que cela, appelez Ens.Director:StopProduction avec un délai plus long.
  • Le délai d'arrêt est un paramètre de production. Vous pouvez le modifier pour une valeur plus importante. Ce paramètre s'applique au portail de gestion du système.
  • Exécuter un code arbitraire lors d'un arrêt de production en implémentant une méthode OnStop.
  • L'arrêt de la production est un événement contrôlable, vous pouvez toujours voir qui et quand a fait cela dans le journal d'audit.

Ce qui est important ici, c'est que la production est la somme totale des Business Hosts :

  • Le démarrage de la production signifie le démarrage de tous les Business Hosts activés.
  • L'arrêt de la production signifie l'arrêt de tous les Business Hosts en cours d'exécution.
  • La mise à jour de la production consiste à calculer un sous-ensemble de Business Hosts qui sont obsolètes, de sorte qu'ils sont d'abord arrêtés, puis redémarrés immédiatement après. En outre, un Business Host nouvellement ajouté est seulement démarré, et un Business Host supprimé de la production est seulement arrêté.

Cela nous amène au cycle de vie des Business Hosts.

Démarrage du Business Host

Les Business Hosts sont composés de Business Hosts Jobs identiques (en fonction de la valeur du paramètre Pool Size). Le démarrage d'un Business Host implique le démarrage de tous les Business Hosts Jobs. Ils sont démarrés en parallèle.

Business Host Job individuel commence comme ceci :

  1. Interopérabilité de JOBs est un nouveau processus qui deviendrait un Business Host Job.
  2. Le nouveau processus s'enregistre en tant que job d'interopérabilité.
  3. Le code du Business Host et le code de l'adaptateur (Adapter) sont chargés dans la mémoire du processus.
  4. Les paramètres relatifs à un Business Host et à un adaptateur sont chargés dans la mémoire. L'ordre de priorité est le suivant a. Paramètres de production (remplacent les paramètres par défaut du système et les paramètres de classe). b. Paramètres par défaut du système (prévalent sur les paramètres de classe). c. Paramètres de classe.
  5. Le travail est prêt et commence à accepter des messages.

Une fois le point (4) effectué, la tâche ne peut plus modifier les paramètres ou le code. Ainsi, lorsque vous importez un nouveau code et de nouveaux paramètres par défaut, cela n'affecte pas les tâches d'interopérabilité en cours d'exécution.

Arrêt de Business Host

L'arrêt du Business Host Job signifie le suivant :

  1. L'interopérabilité ordonne à Job d'arrêter toute acceptation de messages/entrées.
  2. S'il y a un message actif, le Business Host Job dispose d'un délai de quelques secondes pour le traiter (en le complétant - en complétant la méthode OnMessage pour BO, OnProcessInput pour BS, la méthode d'état S<int> pour les BP BPL, et la méthode On* pour les BP).
  3. Si un message actif n'a pas été traité avant le timeout et force=0, la mise à jour de la production échoue pour ce Business Host (et vous verrez un bouton rouge Update dans le SMP).
  4. L'arrêt réussit si l'un des éléments de cette liste est vrai :
    • Pas de message actif
    • Le message actif a été traité avant le timeout.
    • Le message actif n'a pas été traité avant le timeout MAIS force=1.
  5. Le travail est désenregistré auprès de l'interopérabilité et s'arrête.

Mise à jour de Business Host

La mise à jour du Business Host signifie l'arrêt des tâches en cours d'exécution pour le Business Host et le démarrage de nouvelles tâches.

Les régles métier "Business Rules", les régles de routage "Routing Rules" et les DTL

Tous les Business Hosts commencent immédiatement à utiliser les nouvelles versions des régles Business Rules, Routing Rules et des DTL dès qu'elles sont disponibles. Le redémarrage d'un Business Host n'est pas nécessaire pour cela.

Mises à jour hors ligne

Il arrive cependant que les mises à jour de la production nécessitent l'arrêt de certains Business Hosts.

Les régles dépendent du nouveau code

Considérons la situation. Vous disposez d'une règle de routage Routing Rule X qui achemine les messages vers le processus Business Process A ou B en fonction de critères arbitraires. Dans un nouveau commit, vous ajoutez simultanément:

  • le processus Business Process C
  • Une nouvelle version de Routing Rule X, qui achemine les messages vers A, B ou C.

Dans ce scénario, vous ne pouvez pas charger la règle d'abord et mettre à jour la production ensuite. En effet, la règle nouvellement compilée commencerait immédiatement à router les messages vers le Business Process C, qu'InterSystems IRIS n'a peut-être pas encore compilé, ou que l'interopérabilité n'a pas encore mis à jour pour l'utiliser. Dans ce cas, vous devez désactiver le Business Host avec une règle de routage, mettre à jour le code, mettre à jour la production et réactiver le Business Host.

Remarques:

  • Si vous mettez à jour une production à l'aide du fichier de déploiement de la production, tous les BH concernés seront automatiquement désactivés/activés.
  • Pour les hôtes invoqués par InProc, la compilation invalide le cache de l'hôte particulier détenu par l'appelant.

Dépendances entre Business Hosts

Les dépendances entre les Business Hosts sont essentielles. Imaginons que vous ayez des processus Business Hosts A et B, dans lesquels A envoie des messages à B. Dans un nouveau commit, vous ajoutez simultanément :

  • Une nouvelle version du Processus A, qui définit une nouvelle propriété X dans une demande adressée à B
  • Une nouvelle version du Processus B qui peut traiter une nouvelle propriété X

Dans ce scénario, nous DEVONS mettre à jour le Processus B d'abord et le Processus A ensuite. Vous pouvez procéder de deux manières :

  • Désactiver les Business Hosts pendant la durée de la mise à jour.
  • Diviser la mise à jour en deux parties : d'abord, mettre à jour le Processus B uniquement, et ensuite, dans une mise à jour séparée, commencer à lui envoyer des messages à partir du Processus A.

Une variante plus difficile de ce thème, où les nouvelles versions des Processus A et B sont incompatibles avec les anciennes versions, nécessite un arrêt des Business Hosts.

Files d'attente

Si vous savez qu'après la mise à jour, un Business Host ne pourra plus traiter les anciens messages, vous devez vous assurer que la file d'attente du Business Host est vide avant la mise à jour. Pour ce faire, désactivez tous les Business Hosts qui envoient des messages au Business Host et attendez que sa file d'attente soit vide.

Changement d'état dans les BPL Business Processes

Tout d'abord, une petite introduction sur le fonctionnement des BPL BP. Après avoir compilé un BPL BP, deux classes sont créées dans le paquet, avec le même nom qu'une classe BPL complète :

  • La classe Thread1 contient les méthodes S1, S2, .... SN, qui correspondent à des activités au sein de BPL
  • La classe Context contient toutes les variables de contexte ainsi que le prochain état que BPL exécutera (c'est-à-dire S5).

La classe BPL est également persistante et stocke les demandes en cours de traitement.

BPL fonctionne en exécutant des méthodes S dans une classe Thread et en mettant à jour la table de la classe BPL, la table Context et la table Thread1, où un message "en cours de traitement" est une ligne dans un tableau BPL. Une fois la requête traitée, BPL supprime les entrées BPL, Context et Thread. Puisque les BPL BP sont asynchrones, une tâche BPL peut traiter simultanément de nombreuses requêtes en sauvegardant des informations entre les appels S et en passant d'une requête à l'autre. Par exemple, BPL traite une requête jusqu'à ce qu'il arrive à une activité sync - en attendant une réponse de BO. Il sauvegarde le contexte actuel sur le disque, avec la propriété %NextState (dans la classe Thread1) fixée à la méthode S de l'activité de réponse, et travaille sur d'autres requêtes jusqu'à ce que BO réponde. Après la réponse de BO, BPL charge le contexte en mémoire et exécute la méthode correspondant à un état sauvegardé dans la propriété %NextState.

Maintenant, que se passe-t-il lorsque nous mettons à jour le BPL ? Tout d'abord, nous devons vérifier qu'au moins une des deux conditions est remplie :

  • Pendant la mise à jour, le tableau Contexte est vide, ce qui signifie qu'aucun message actif n'est en cours de traitement.
  • Les nouveaux états (New States) sont les mêmes que les anciens (Old States), ou de nouveaux états sont ajoutés à la suite des anciens .

Si au moins une condition est remplie, nous sommes prêts à démarrer. Soit il n'y a pas de demandes de pré-mise à jour à traiter par BPL après la mise à jour, soit les états sont ajoutés à la fin, ce qui signifie que les anciennes demandes peuvent également être traitées (en supposant que les demandes de pré-mise à jour sont compatibles avec les activités et le traitement de BPL après la mise à jour).

Mais que se passe-t-il si vous avez des demandes actives en cours de traitement et que BPL change l'ordre des états ? Idéalement, si vous pouvez attendre, désactivez les appelants BPL et attendez que la file d'attente soit vide. Vérifiez que le tableau Contexte est également vide. N'oubliez pas que la file d'attente n'affiche que les demandes non traitées, et que le tableau Contexte stocke les demandes en cours de traitement, de sorte qu'il peut arriver qu'un BPL très occupé affiche une file d'attente nulle, et c'est normal. Ensuite, désactivez le BPL, effectuez la mise à jour et activez tous les Business Hosts précédemment désactivés.

Si ce n'est pas possible (généralement dans le cas où le BPL est très long, par exemple, je me souviens avoir mis à jour un BPL qui prenait environ une semaine pour traiter une demande, ou si la fenêtre de mise à jour est trop courte), utilisez l'outil BPL versioning.

Vous pouvez également écrire un script de mise à jour. Dans ce script de mise à jour, associez les anciens next states aux nouveaux next states et exécutez-le sur le tableau Thread1 afin que le BPL mis à jour puisse traiter les anciennes requêtes. BPL, bien sûr, doit être désactivé pendant la durée de la mise à jour. Ceci dit, il s'agit d'une situation extrêmement rare, et généralement, vous n'avez pas besoin de faire cela, mais si jamais vous devez le faire, voici comment procéder.

Conclusion

L'interopérabilité met en œuvre un algorithme sophistiqué pour minimiser le nombre d'actions nécessaires pour actualiser la production après la modification du code sous-jacent. Appelez UpdateProduction avec un délai d'attente sûr à chaque mise à jour de SDS. Pour chaque mise à jour de code, vous devez décider d'une stratégie de mise à jour.

La réduction de la quantité de code compilé à l'aide de git diffs permet de réduire le temps de compilation, mais la "mise à jour" du code en lui-même et sa recompilation ou la "mise à jour" des paramètres avec les mêmes valeurs ne déclenchent pas ou ne requièrent pas de mise à jour de la production.

La mise à jour et la compilation des règles de gestion "Business Rule", des règles de routage "Routing Rules" et des DTL les rendent immédiatement accessibles sans mise à jour de la production.

Enfin, la mise à jour de la production est une opération sûre qui ne nécessite généralement pas de temps d'arrêt.

Liens

L'auteur tient à remercier @James MacKeith, @Dmitry Zasypkin et @Regilo Regilio Guedes de Souza pour leur aide précieuse dans la rédaction de cet article.

0
0 89
Article Pierre LaFay · Jan 7, 2024 8m read

Introduction

Cet article vise à explorer le fonctionnement du système FHIR-PEX et a été développé, en tirant parti des capacités d'InterSystems IRIS.

En rationalisant l'identification et le traitement des examens médicaux dans les centres de diagnostic clinique, notre système vise à améliorer l'efficacité et la précision des flux de travail de soins de santé. En intégrant les normes FHIR à la base de données InterSystems IRIS Java-PEX, le système aide les professionnels de santé avec des capacités de validation et de routage, contribuant ainsi à améliorer la prise de décision et les soins aux patients.

how it works

  • Interopérabilité IRIS : Reçoit les messages au standard FHIR, garantissant l'intégration et la compatibilité avec les données de santé.

  • Traitement de l'information avec 'PEX Java' : Traite les messages au format FHIR et les dirige vers des sujets Kafka en fonction de règles configurées globalement dans la base de données, facilitant ainsi le traitement et le routage efficaces des données, en particulier pour les examens dirigés vers la quarantaine.

  • Gestion des retours Kafka via un backend Java externe : Interprète uniquement les examens dirigés vers la quarantaine, permettant au système de gérer les retours de Kafka via un backend Java externe. Il facilite la génération d'informations pronostiques pour les professionnels de la santé grâce à l'IA générative, en s'appuyant sur les consultations des résultats d'examens précédents pour les patients respectifs.

Development

Grâce au PEX (Production EXtension) d'InterSystems, un outil d'extensibilité permettant d'améliorer et de personnaliser le comportement du système, nous avons élaboré une Opération Métier. Ce composant est chargé de traiter les messages entrants au format FHIR au sein du système. Comme exemple suivant :

import com.intersystems.enslib.pex.*;
import com.intersystems.jdbc.IRISObject;
import com.intersystems.jdbc.IRIS;
import com.intersystems.jdbc.IRISList;
import com.intersystems.gateway.GatewayContext;

import org.apache.kafka.clients.producer.*;
import org.apache.kafka.common.serialization.*;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

public class KafkaOperation extends BusinessOperation {
// Connection to InterSystems IRIS
private IRIS iris;

// Connection to Kafka
private Producer<Long, String> producer;

// Kafka server address (comma separated if several)
public String SERVERS;

// Name of our Producer
public String CLIENTID;

/// Path to Config File
public String CONFIG;

public void OnInit() throws Exception {
[...]
}

public void OnTearDown() throws Exception {
[...]
}

public Object OnMessage(Object request) throws Exception {
    IRISObject req = (IRISObject) request;
    LOGINFO("Received object: " + req.invokeString("%ClassName", 1));

    // Create record
    String value = req.getString("Text");
    String topic = getTopicPush(req);
    final ProducerRecord<Long, String> record = new ProducerRecord<>(topic, value);

    // Send new record
    RecordMetadata metadata = producer.send(record).get();

    // Return record info
    IRISObject response = (IRISObject)(iris.classMethodObject("Ens.StringContainer","%New",topic+"|"+metadata.offset()));
    return response;
}

private Producer<Long, String> createProducer() throws IOException {
[...]
}

private String getTopicPush(IRISObject req) {
[...]
}

[...]
}

`

Au sein de l'application, la méthode getTopicPush se charge d'identifier le sujet auquel le message sera envoyé.

La détermination du sujet auquel le message sera envoyé dépend de l'existence d'une règle dans la globale "quarantineRule", telle que lue dans IRIS.

String code = FHIRcoding.path("code").asText();
String system = FHIRcoding.path("system").asText();

IRISList quarantineRule = iris.getIRISList("quarantineRule",code,system);

 String reference = quarantineRule.getString(1);
 String value = quarantineRule.getString(2);

 String observationValue = fhir.path("valueQuantity").path("value").asText()

When the global ^quarantineRule exists, validation of the FHIR object can be validated.

private boolean quarantineValueQuantity(String reference, String value, String observationValue) {
    LOGINFO("quarantine rule reference/value: " + reference + "/" + value);
    double numericValue = Double.parseDouble(value);
    double numericObservationValue = Double.parseDouble(observationValue);

    if ("<".equals(reference)) {
        return numericObservationValue < numericValue;
    }
    else if (">".equals(reference)) {
        return numericObservationValue > numericValue;
    }
    else if ("<=".equals(reference)) {
        return numericObservationValue <= numericValue;
    }
    else if (">=".equals(reference)) {
        return numericObservationValue >= numericValue;
    }
    
    return false;
}

Exemple pratique :

Lors de la définition d'une globale, telle que :

Set ^quarantineRule("59462-2","http://loinc.org") = $LB(">","500") 

Ceci établit une règle pour le code "59462-2" et le système ""http://loinc.org"" dans la globale ^quarantineRule , spécifiant une condition dans laquelle la valeur supérieure à 500 est définie comme quarantaine. Dans l'application, la méthode getTopicPush peut ensuite utiliser cette règle pour déterminer le sujet approprié pour envoyer le message en fonction du résultat de la validation.

Compte tenu de l'affectation, le JSON ci-dessous serait envoyé en quarantaine car il correspond à la condition spécifiée en ayant :

 {
          "system": "http://loinc.org",
          "code": "59462-2",
          "display": "Testosterone"
}

"valueQuantity": { "value": 550, "unit": "ng/dL", "system": "http://unitsofmeasure.org", "code": "ng/dL" }

FHIR Observation:

{
    "resourceType": "Observation",
    "id": "3a8c7d54-1a2b-4c8f-b54a-3d2a7efc98c9",
    "status": "final",
    "category": [
      {
        "coding": [
          {
            "system": "http://terminology.hl7.org/CodeSystem/observation-category",
            "code": "laboratory",
            "display": "laboratory"
          }
        ]
      }
    ],
    "code": {
      "coding": [
        {
          "system": "http://loinc.org",
          "code": "59462-2",
          "display": "Testosterone"
        }
      ],
      "text": "Testosterone"
    },
    "subject": {
      "reference": "urn:uuid:274f5452-2a39-44c4-a7cb-f36de467762e"
    },
    "encounter": {
      "reference": "urn:uuid:100b4a8f-5c14-4192-a78f-7276abdc4bc3"
    },
    "effectiveDateTime": "2022-05-15T08:45:00+00:00",
    "issued": "2022-05-15T08:45:00.123+00:00",
    "valueQuantity": {
      "value": 550,
      "unit": "ng/dL",
      "system": "http://unitsofmeasure.org",
      "code": "ng/dL"
    }
}

L'application Java Quarkus

Après envoi sur le sujet souhaité, une application Quarkus Java a été construite pour recevoir les examens en quarantaine. @ApplicationScoped public class QuarentineObservationEventListener {

@Inject
PatientService patientService;

@Inject
EventBus eventBus;

@Transactional
@Incoming("observation_quarantine")
public CompletionStage<Void> onIncomingMessage(Message<QuarentineObservation> quarentineObservationMessage) {
	var quarentineObservation = quarentineObservationMessage.getPayload();
	var patientId = quarentineObservation.getSubject()
			.getReference();
	var patient = patientService.addObservation(patientId, quarentineObservation);
	publishSockJsEvent(patient.getId(), quarentineObservation.getCode()
			.getText());
	return quarentineObservationMessage.ack();
}

private void publishSockJsEvent(Long patientId, String text) {
	eventBus.publish("monitor", MonitorEventDto.builder()
			.id(patientId)
			.message(" is on quarentine list by observation ." + text)
			.build());
}
 }

Ce segment du système est chargé de conserver les informations reçues de Kafka, de les stocker dans les observations du patient dans la base de données et de notifier l'événement au moniteur.

The monitor

Enfin, le moniteur du système est chargé de fournir une visualisation frontale simple. Cela permet aux professionnels de la santé d’examiner les données des patients/examens et de prendre les mesures nécessaires.

Implementation of langchainPT

Grâce au moniteur, le système permet aux professionnels de la santé de demander des recommandations à l'IA générative.

@Unremovable
@Slf4j
@ApplicationScoped
public class PatientRepository {
	@Tool("Get anamnesis information for a given patient id")
	public Patient getAnamenisis(Long patientId) {
		log.info("getAnamenisis called with id " + patientId);
		Patient patient = Patient.findById(patientId);
		return patient;
	}

	@Tool("Get the last clinical results for a given patient id")
	public List<Observation> getObservations(Long patientId) {
		log.info("getObservations called with id " + patientId);
		Patient patient = Patient.findById(patientId);
		return patient.getObservationList();
	}

}

suivre la mise en œuvre de Langchain4j

@RegisterAiService(chatMemoryProviderSupplier = RegisterAiService.BeanChatMemoryProviderSupplier.class, tools = {PatientRepository.class})
public interface PatientAI {

	@SystemMessage("""
			You are a health care assistant AI. You have to recommend exams for patients based on history information.
			""")
	@UserMessage("""
			 Your task is to recommend clinical exams for the patient id {patientId}.

			 To complete this task, perform the following actions:
			 1 - Retrieve anamnesis information for patient id {patientId}.
			 2 - Retrieve the last clinical results for patient id {patientId}, using the property 'name' as the name of exam and 'value' as the value.
			 3 - Analyse results against well known conditions of health care.

			 Answer with a **single** JSON document containing:
			 - the patient id in the 'patientId' key
			 - the patient weight in the 'weight' key
			 - the exam recommendation list in the 'recommendations' key, with properties exam, reason and condition.
			 - the 'explanation' key containing an explanation of your answer, especially about well known diseases.

			Your response must be just the raw JSON document, without ```json, ``` or anything else.
			 """)
	String recommendExams(Long patientId);
}

Le système peut ainsi aider les professionnels de santé à prendre des décisions et à mener des actions.

Video demo

VIDEO

Authors

NOTE:

L'application https://openexchange.intersystems.com/package/fhir-pex participe actuellement au concours InterSystems Java 2023. N'hésitez pas à explorer davantage la solution et n'hésitez pas à nous contacter si vous avez des questions ou avez besoin d'informations supplémentaires. Nous vous recommandons d'exécuter l'application dans votre environnement local pour une expérience pratique. Merci pour l'opportunité 😀!

0
0 124
Question Cyril Grosjean · Déc 12, 2023

Bonjour,

Nous avons voulu mettre en pré-production un flux 100% python, cependant lorsqu'on a lancé la commande iop pour tester avec l'utilisateur qui va déployer via une CI/CD le code, voici ce qu'on obtient:

ssh.gitlab est notre utilisateur, nous sommes sur un serveur Windows 10 et ssh.gitlab est admin.

Y a-t-il des modifications à faire sur le portail d'IRIS ? (Un utilisateur est créé pour la CI/CD suite à ce post)

Merci d'avance !

Cordialement,

Cyril

2
0 65
Question Laurent Vilcoq · Nov 16, 2023

Bonjour,

Je dois récupérer quotidiennement la totalité des données d'une vue SQL externe pour générer un fichier csv unique. J'étais partie sur l'utilisation d'un service de type EnsLib.SQL.Service.GenericService mais cela ne me convient pas puisque chaque ligne de résultat de la requête SQL génère un message et une trace différents. Dois-je passer par une table de lien ? Créer un service de toute pièce en implémentant le OnProcessInput() ? Autre ?

Merci par avance pour votre aide.

Bien cordialement,

2
1 159
Question Cyril Grosjean · Oct 11, 2023

Bonjour,

J'ai un soucis depuis quelques jours que je n'arrive pas à régler après pas mal de recherche sur le forum communautaire français et anglais, ainsi que la documentation InterSystems. J'ai deux namespaces : "TEST" et "SUPPLY_CHAIN" ainsi qu'une fonction en python identique compilée dans les deux namespaces :

ClassMethod testPython() As%Status [ Language = python ]

{

    print("Ok")

}

Lorsque j'appelle depuis le terminal iris cette fonction comme ceci:

do##class(TEST.maclasse).testPython()


Cela me retourne bien "ok"

7
0 168
Question Julia Pertin · Sept 18, 2023

Bonjour à tous, 

Pour un interop je dois récupérer en entrée un json d'une API REST. J'essaie donc de passer le %Net.HttpRequest or j'obtiens cette erreur : 

J'ai mis cette classe en entrée du business process et j'ai un business service qui appel à intervalle régulier ce business process : 

Pouvez-vous m'aider s'il vous plait ? 

1
1 82
Article Sylvain Guilbaud · Sept 14, 2023 8m read

Aperçu

La documentation en ligne contient une référence expliquant comment définir et utiliser les requêtes de classes.

La personnalisation des procédures stockées en ObjectScript s'est avérée utile pour accéder au stockage NoSQL et à la messagerie externe via l'intégration, afin de présenter la sortie sous forme de tableau.

Par exemple : une application qui utilise déjà 90 % d'interaction SQL depuis un frontal peut alors également étendre cet accès aux 10 % restants des fonctionnalités requises de la plate-forme, via le même accès SQL.

0
0 106
Article Guillaume Rongier · Juil 24, 2023 7m read

Je suis fier d'annoncer la nouvelle version du logiciel iris-pex-embedded-python (v2.3.1) avec une nouvelle interface en ligne de commande.

Cette ligne de commande est appelée iop et signifie Interoperability On Python (interopérabilité sur Python).

Tout d'abord, j'aimerais présenter en quelques mots le projet et les principaux changements depuis la version 1.

Un bref historique du projet

La version 1.0 était une preuve de concept visant à montrer comment le cadre d'interopérabilité d'IRIS peut être utilisé avec une approche python first (priorité à Python) tout en restant compatible avec n'importe quel code ObjectScript existant.

Qu'est-ce que cela signifie ? Cela signifie que tout développeur python peut utiliser le cadre d'interopérabilité d'IRIS sans aucune connaissance d'ObjectScript.

Exemple :

from grongier.pex import BusinessOperation

class MyBusinessOperation(BusinessOperation):

    def on_message(self, request):
        self.log.info("Demande reçue")

Formidable, n'est-ce pas ?

Avec la version 1.1, j'ai ajouté la possibilité d'enregistrer ces classes python dans IRIS avec une fonction d'aide "help".

from grongier.pex import Utils

Utils.register_file("/src/MyBusinessOperation.py")

La version 2.0 est une version majeure car on peut maintenant installer ce projet avec pip.

pip install iris-pex-embedded-python

Quoi de neuf dans la version 2.3.1

La version 2.3.1 est une version majeure car elle introduit une nouvelle interface en ligne de commande.

Cette interface en ligne de commande peut être utilisée avec ce projet python basé sur ce module ou peut-être avec des projets qui n'utilisent pas ce module.

Laissez-moi la présenter et expliquer pourquoi elle peut être utilisée dans des projets non python.

L'interface en ligne de commande

La ligne de commande fait partie de ce projet, pour l'installer il suffit d'installer ce projet avec pip.

pip install iris-pex-embedded-python

Vous pouvez ensuite utiliser la ligne de commande iop pour lancer le cadre d'interopérabilité.

iop

résultat :

utilisation: iop [-h] [-d DEFAULT] [-l] [-s START] [-k] [-S] [-r] [-M MIGRATE] [-e EXPORT] [-x] [-v] [-L]
les arguments optionnels:
  -h, --help            affichage de  help (aide) et du nom de production par défaut
  -d DEFAULT, --default DEFAULT
                        définition de la production par défaut
  -l, --lists           liste de productions
  -s START, --start START
                        démarrage de la production
  -k, --kill            Suppression de la production (arrêt forcé)
  -S, --stop            Arrêt de la production
  -r, --restart         redémarrage de la production
  -M MIGRATE, --migrate MIGRATE
                        migration de la production et des classes avec un fichier de configuration
  -e EXPORT, --export EXPORT
                        exportation de la production
  -x, --status          état de la production
  -v, --version         version d''affichage
  -L, --log             affichage du journal

production par défaut : UnitTest.Production

Voici quelques exemples.

help (aide)

La commande "help" affiche l'aide et le nom de production par défaut.

iop -h

résultat :

utilisation: python3 -m grongier.pex [-h] [-d DEFAULT] [-l] [-s START] [-k] [-S] [-r] [-M MIGRATE] [-e EXPORT] [-x] [-v] [-L]
...
production par défaut : PEX.Production

default (par défaut)

La commande "default" permet de définir la production par défaut.

Si aucun argument n'est fourni, la production par défaut est affichée.

iop -d

résultat :

production par défaut : PEX.Production

Si un argument est fourni, la production par défaut est définie.

iop -d PEX.Production

lists (les listes)

La commande "lists" permet de dresser la liste des productions.

iop -l

utilisation :

{
    "PEX.Production": {
        "Status": "Stopped",
        "LastStartTime": "2023-05-31 11:13:51.000",
        "LastStopTime": "2023-05-31 11:13:54.153",
        "AutoStart": 0
    }
}

start (lancement)

La commande "start" permet de lancer une production.

Pour quitter la commande, il faut appuyer sur CTRL+C.

iop -s PEX.Production

Si aucun argument n'est donné, la commande "start" lance la production par défaut.

iop -s

résultat :

2021-08-30 15:13:51.000 [PEX.Production] INFO: Starting production
2021-08-30 15:13:51.000 [PEX.Production] INFO: Starting item Python.FileOperation
2021-08-30 15:13:51.000 [PEX.Production] INFO: Starting item Python.EmailOperation
...

kill (suppression)

La commande "kill" peut supprimer une production (arrêt forcé).

La commande "kill" est la même que la commande stop mais avec un arrêt forcé.

La commande "Kill" ne prend pas d'argument parce qu'une seule production peut être en cours d'exécution.

iop -k

stop (arrêt)

La commande "stop" permet d'arrêter une production.

La commande "stop" ne prend pas d'argument parce qu'une seule production peut être en cours d'exécution.

iop -S

restart (redémarrage)

La commande "restart" permet de relancer une production.

La commande "restart" ne prend pas d'argument parce qu'une seule production peut être en cours d'exécution.

iop -r

migrate (migration)

La commande "migrate" permet de migrer une production et des classes avec un fichier de configuration.

La commande "migrate" doit prendre le chemin absolu du fichier de configuration.

Le fichier de configuration doit se trouver dans le même dossier que le code python.

iop -M /tmp/settings.py

export (exportation)

La commande "export" permet d'exporter une production.

Si aucun argument n'est donné, la commande "export" exporte la production par défaut.

iop -e

Si un argument est donné, la commande "export" exécute la production indiquée dans l'argument.

iop -e PEX.Production

résultat :

{
    "Production": {
        "@Name": "PEX.Production",
        "@TestingEnabled": "true",
        "@LogGeneralTraceEvents": "false",
        "Description": "",
        "ActorPoolSize": "2",
        "Item": [
            {
                "@Name": "Python.FileOperation",
                "@Category": "",
                "@ClassName": "Python.FileOperation",
                "@PoolSize": "1",
                "@Enabled": "true",
                "@Foreground": "false",
                "@Comment": "",
                "@LogTraceEvents": "true",
                "@Schedule": "",
                "Setting": [
                    {
                        "@Target": "Adapter",
                        "@Name": "Charset",
                        "#text": "utf-8"
                    },
                    {
                        "@Target": "Adapter",
                        "@Name": "FilePath",
                        "#text": "/irisdev/app/output/"
                    },
                    {
                        "@Target": "Host",
                        "@Name": "%settings",
                        "#text": "path=/irisdev/app/output/"
                    }
                ]
            }
        ]
    }
}

status (état)

La commande "status" permet d'indiquer l'état d'une production.

La commande "status" ne prend pas d'argument parce qu'une seule production peut être en cours d'exécution.

iop -x

résultat :

{
    "Production": "PEX.Production",
    "Status": "stopped"
}

Un état peut être :

  • arrêté
  • en cours d'exécution
  • suspendu
  • compliqué

version

La commande "version" permet d'afficher la version.

iop -v

résultat :

2.3.0

log (journal)

La commande "log" permet d'afficher le journal.

Pour quitter la commande, il faut appuyer sur CTRL+C.

iop -L

résultat :

2021-08-30 15:13:51.000 [PEX.Production] INFO: Starting production
2021-08-30 15:13:51.000 [PEX.Production] INFO: Starting item Python.FileOperation
2021-08-30 15:13:51.000 [PEX.Production] INFO: Starting item Python.EmailOperation
...

Peut-on l'utiliser en dehors du projet iris-pex-embedded-python ?

À vous de choisir.

Mais, avant de vous quitter, laissez-moi vous expliquer pourquoi je pense que cela peut être utilisé en dehors du projet iris-pex-embedded-python.

Tout d'abord, parce que cela permet d'interagir avec la production sans avoir besoin d'utiliser un shell iris. Cela signifie qu'il est plus facile à l'utiliser dans un script.

Deuxièmement, parce que settings.py peut être utilisé pour importer la production et les classes avec des variables d'environnement.

Voici un exemple de settings.py :

import os

PRODUCTIONS = [
        {
            'UnitTest.Production': {
                "Item": [
                    {
                        "@Name": "Python.FileOperation",
                        "@ClassName": "Python.FileOperation",
                        "Setting": {
                            "@Target": "Host",
                            "@Name": "%settings",
                            "#text": os.environ['SETTINGS']
                        }
                    }
                ]
            }
        }
    ]

Faites attention à la valeur #text. C'est une variable d'environnement. Pas mal, non ?

Est-ce que vous vous voyez utiliser cet outil en ligne de commande, cela vaut-il la peine de continuer à le développer ?

Merci pour avoir lu cet article et vos commentaires sont les bienvenus.

0
0 78
Article Guillaume Rongier · Juil 12, 2023 4m read

L' adaptateur Telegram pour InterSystems IRIS sert de pont entre la populaire plateforme de messagerie Telegram et InterSystems IRIS, facilitant une communication et un échange de données transparents. En exploitant les capacités de l'API Telegram, l'adaptateur permet aux développeurs de créer des chatbots robustes, d'automatiser des tâches et d'intégrer Telegram aux applications d'InterSystems IRIS.

Les scénarios les plus courants dans lesquels l'adaptateur Telegram peut être utilisé sont les suivants :

0
0 114
Article Sylvain Guilbaud · Avr 26, 2023 3m read

Mise à jour : ajout du support pour le modèle de régression Bonjour à toutes et à tous !

Dans ce bref article, je vous montrerai comment écrire un adaptateur pour IRIS Interoperability afin d'utiliser des modèles ML gérés par IRIS IntegratedML.

L'adaptateur

L'adaptateur utilise simplement les fonctions SQL d'IntegratedML comme prédiction PREDICT et probabilité PROBABILITY, pour obtenir la classe prédite par le modèle et sa probabilité. Il s'agit d'un simple SQL :
![code1][code1] [code1]: https://raw.githubusercontent.com/jrpereirajr/interoperability-integratedml-adapter/master/img/how-it-works-1.png
Notez que le nom du modèle est référencé par la propriété Model. Cette propriété doit être définie dans la classe hôte qui utilise l'adaptateur, sinon une exception sera produite. Par exemple:


La liste des modèles dans les paramètres de l'adaptateur est établie en deux étapes :
  1. Création d'une méthode dans une classe qui étend %ZEN.Portal.ContextSearch pour charger tous les modèles de classification et les renvoyer (dc.Ens.Adapter.ClassficationMLContextSearch)
    ![code2][code2] [code2]: https://raw.githubusercontent.com/jrpereirajr/interoperability-integratedml-adapter/master/img/how-it-works-2.png
  2. Configuration d'une telle classe et d'une telle méthode comme chargeur pour la propriété Model dans le paramètre SETTINGS de la classe adaptateur (dc.Ens.Adapter.ClassificationMLAdapter)
    ![code3][code3] [code3]: https://raw.githubusercontent.com/jrpereirajr/interoperability-integratedml-adapter/master/img/how-it-works-3.png
    Pour les modèles de régression, il existe la classe dc.Ens.Adapter.RegressionMLContextSearch, qui charge tous les modèles de régression.

Dans ce cas, le filtre MODE_TYPE est réglé sur "régression" au lieu de "classification" :

Utilisation de l'adaptateur

Pour la démonstration, j'ai simulé un système simple de paiement par carte de crédit avec des fonctions de détection des fraudes, à l'aide d'un modèle de classification ML. Lorsqu'une transaction suspecte est détectée, une alerte est émise.

Pour utiliser l'adaptateur, créez une classe hôte (une classe de processus métier "Business Process" ou d'opération métier "Business Operation") qui utilise comme adaptateur la classe dc.ENS.Adapter.ClassificationMLAdapter.
![code4][code4] [code4]: https://raw.githubusercontent.com/jrpereirajr/interoperability-integratedml-adapter/master/img/how-to-use-it-1.png
Vous pouvez maintenant utiliser la méthode Classify() de l'adaptateur et fournir un échantillon des caractéristiques attendues par le modèle :
Pour l'utiliser, créez une classe hôte (une classe de processus métier ou d'opération métier) qui utilise comme adaptateur la classe dc.ENS.Adapter.ClassificationMLAdapter
![code5][code5] [code5]: https://raw.githubusercontent.com/jrpereirajr/interoperability-integratedml-adapter/master/img/how-to-use-it-2.png
Vous pouvez les utiliser selon vos besoins. Dans l'exemple, seul le résultat de la prédiction de la fraude était nécessaire, la classe d'opération métier "Business Operation" utilise donc simplement la valeur renvoyée dans la propriété "Predicted" :
![code6][code6] [code6]: https://raw.githubusercontent.com/jrpereirajr/interoperability-integratedml-adapter/master/img/how-to-use-it-4.png
Pour les modèles de régression, les résultats sont modélisés par la classe dc.Ens.Adapter.RegressionResult. Cette classe possède une propriété appelée Estimated.

Pour les modèles de régression, les résultats sont modélisés par la classe dc.Ens.Adapter.RegressionResult. Cette classe possède une propriété appelée Estimated. Pour obtenir une valeur estimée à partir d'un échantillon, la classe d'adaptateur pour le modèle de régression dispose de la méthode "Estimate".

Le résultat final est affiché ci-dessous :
![code7][code7] [code7]: https://raw.githubusercontent.com/jrpereirajr/interoperability-integratedml-adapter/master/img/KMWbgqw1C9.gif
Le code complet est disponible dans OpenExchange. J'espère que cela pourra vous être utile. José

0
0 51
Article Irène Mykhailova · Mars 15, 2023 2m read

Bonjour à tous !

Je partage avec vous un outil d'ingestion de données que nous avons utilisé dans certains projets.

DataPipe est un framework d'interopérabilité pour l'ingestion de données dans InterSystems IRIS de manière flexible. Il vous permet de recevoir des données de sources externes, de normaliser et de valider les informations et enfin d'effectuer toutes les opérations dont vous avez besoin avec vos données.

Modèle

En premier lieu, vous devez définir un modèle. Un modèle est simplement une classe qui s'étend à partir de DataPipe.Model où vous devez implémenter quelques méthodes :

Dans le modèle, vous spécifiez comment vous allez sérialiser / désérialiser les données, comment vous les normalisez et les validez et enfin quelle opération vous voulez effectuer avec vos données une fois qu'elles sont normalisées et validées.

Here you can find a full example of a DataPipe model.

Composants d'interopérabilité

Après avoir défini le modèle, vous pouvez ajouter les composants dont vous avez besoin à une production d'interopérabilité.

Vous devez mettre en place un processus d'ingestion qui doit comprendre les éléments suivants :

  • La transformation Input > InboxAttributes où vous spécifiez comment extraire les attributs qui décrivent vos données d'entrée. Ces attributs peuvent être utilisés pour rechercher les données traitées.
  • La transformation Input > Model où vous implémentez comment convertir les données entrantes dans votre modèle DataPipe.

Les autres composantes sont déjà préconstruites dans DataPipe. Vous avez un exemple de production ici.

DatapipeUI

Il existe également une interface utilisateur que vous pouvez utiliser pour gérer les données que vous ingérez dans le système.

Déploiement

Pour le déployer, vous avez besoin d'une instance IRIS d'InterSystems, où vous installez DataPipe (et RESTForms2 pour les API REST) et une application web externe (UI) qui interagira avec cette instance.

Si vous êtes intéressé et que vous souhaitez jeter un coup d'œil et tester cette solution, vous trouverez toutes les informations nécessaires dans le lien Open Exchange.

0
0 122
Article Lorenzo Scalese · Fév 27, 2023 18m read

Salut la communauté,

J'aimerais vous présenter ma dernière application OpenAPI-Suite, c'est un ensemble d'outils permettant de générer du code ObjectScript à partir d'une specification OpenAPI version 3.0. L'application permet de:

  • Générer les classes serveur REST.  C'est assez similaire au code généré par ^%RESTla valeur ajoutée est le support de la version 3.0.
  • Générer les classes pour un client HTTP.
  • Générer une production cliente (business services, business operation, business process, Ens.Request, Ens.Response).
  • Disposer d'une interface web pour générer et télécharger le code ou générer et compiler directement sur le serveur.
  • Convertir les spécifications de version 1.x, 2.x en version 3.0.

Aperçu

OpenAPI-Suite est divisée en plusieurs packages et utilise différentes bibliothèques de la communauté des développeurs ainsi que des services REST publics.  Vous pouvez voir sur le schéma ci-dessous, tous les packages développés et les bibliothèques et services web utilisés:
 

0
0 202
Article Irène Mykhailova · Jan 12, 2023 3m read

Voulez-vous être sûr que vos transformations de données fonctionnent comme prévu avec une seule commande ? Et que diriez-vous d'écrire des tests unitaires pour vos transformations de données de manière simple et rapide ? 

Les transformations de données sont généralement très présentes lorsqu'on parle d'interopérabilité. Ces transformations de données sont utilisées pour convertir les données entre différents systèmes ou applications dans votre code, et elles ont donc un rôle très important à jouer.

Les stratégies de test

Après avoir examiné le concept de la [Pyramide de tests] (https://martinfowler.com/bliki/TestPyramid.html) et certains [articles] (https://medium.com/@timothy.cochran/test-pyramid-the-key-to-good-automated-test-strategy-9f3d7e3c02d5) à ce sujet, on peut se faire une idée rapide du fait qu'il est préférable de disposer d'une base solide de tests automatisés de bas niveau moins coûteux que de tester uniquement l'interface utilisateur.

Dans un contexte d'interopérabilité, j'ai constaté dans plusieurs projets qu'il vaut vraiment la peine d'investir un peu d'effort dans l'écriture de tests unitaires de transformation de données, surtout lorsque nous traitons différents scénarios (par exemple HL7, messages personnalisés, etc.). Cela nous permettra d'être sûrs que notre logique de transformation de données fonctionne comme prévu après l'introduction de nouveaux changements. Même après la résolution d'un problème avec une transformation de données, nous pouvons facilement créer un nouveau test avec le message qui a causé le problème, de sorte que nous sommes sûrs de ne pas obtenir la même erreur à l'avenir.  

Un petit assistant qui utilise le cadre %UnitTest

Pour vous aider à écrire et à exécuter des tests de transformation de données, je partage un exemple qui utilise le cadre [IRIS %UnitTest framework] (https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=TUNT_preface). L'objectif est de vous permettre de définir des ensembles différents de messages d'entrée et de messages de sortie correspondants prévus pour chaque transformation de données à tester, en tant que fichiers texte externes.

Supposons que vous vouliez créer des tests unitaires pour une transformation de données appelée Sample.Health.a31ToPatient, alors vous devez procéder comme suit :

  1. Créez une nouvelle classe étendue DataTransformTestCase. Définissez le paramètre <TestDirectory> comme le répertoire dans lequel vous allez stocker vos tests de transformation de données.

  2. Dans votre <TestDirectory>, créez un sous-répertoire appelé  Sample.Health.a31ToPatient. Ce sous-répertoire stockera les ensembles d'entrées et de sorties attendues que vous souhaitez tester dans la transformation de données.

  3. Dans le sous-répertoire Sample.Health.a31ToPatient is faut ajouter les messages d'entrée et la sortie attendue comme .in.txt and .out.txt.

  4. Lancez vos tests ! Vous pouvez voir les résultats dans le portail %UnitTest Framework dans IRIS. Si vous obtenez une erreur, le fichier *.gen.txt sera généré, afin que vous puissiez comparer la sortie réelle à la sortie attendue et voir ce qui ne va pas.   

 

Lancez l'exemple vous-même !

Vous pouvez télécharger, lancer l'exemple et lire plus de détails dans Open Exchange.

0
0 126
Article Guillaume Rongier · Jan 4, 2023 11m read

Les systèmes EHR (Electronic Health Record) sont modélisés dans un format/structure propriétaire et ne sont pas basés sur des modèles du marché tels que FHIR ou HL7. Certains de ces systèmes peuvent interopérer des données dans un format propriétaire pour FHIR et d'autres modèles de marché, mais pas tous. InterSystems dispose de deux plateformes capables d'interopérer des formats propriétaires pour ceux du marché : InterSystems HealthShare Connect et InterSystems IRIS for Health. La fonctionnalité de transformation (DTL - Data Transformation Language) de ces plateformes peut recevoir des données dans n'importe quel format, structure ou canal de communication (CSV, JSON, XML, et autres via FTP, File, HTTP, etc.) et les transformer directement en formats du marché (FHIR, CDA, HL7, etc.). Cependant, InterSystems dispose d'un format intermédiaire appelé SDA (Summary Document Architecture) qui est utilisé par ces plateformes pour générer sans effort des FHIR STU, R3, R4, HL7v2, HL7v3, etc. En outre, lorsqu'elles sont au format SDA, les données de santé peuvent être conservées dans le RCU HealthShare. Ainsi, le format propriétaire/personnel est d'abord transformé en SDA, puis les données peuvent être automatiquement converties dans n'importe quel format du marché, ainsi que sauvegardées dans HealthShare. Dans cet article, nous allons vous montrer comment transformer des données propriétaires/personnalisées en SDA à l'aide d'IRIS for Health. L'exemple de données que nous avons utilisé a été généré par le projet de génération de données en masse SYNTHEA (https://synthea.mitre.org/downloads). Nous allons convertir 1000 patients d'un fichier CSV en SDA, en utilisant les fonctions d'interopérabilité d'IRIS for Health.

Application de soutien aux articles – custom2sda

Installation de l'application d'exemple qui sera utilisée avec cet article en suivant les instructions :

Si vous voulez installer en utilisant ZPM :

1. Ouvrez le Namespace IRIS avec l'interopérabilité activée.
2. Ouvrez le Terminal et appelez : USER>zpm "install custom2sda"

Si vous voulez installer en utilisant Docker :

1. Clonez Git et tirez le repo dans n'importe quel répertoire local :

$ git clone https://github.com/yurimarx/custom2sda.git

2. Ouvrez le terminal dans ce répertoire et exécutez :

$ docker-compose build

3. Lancez le conteneur IRIS avec votre projet :

$ docker-compose up -d

4. Ouvrez la production (http://localhost:52775/csp/healthshare/user/EnsPortal.ProductionConfig.zen?PRODUCTION=customsda.CustomToSDAProduction) et la lancez. (utilizateur _SYSTEM et le mot de passe SYS). Elle lira le fichier patients.csv et le convertira en SDA.

Créer une carte d'enregistrement CSV pour obtenir les données personnalisées/propriétaires

Dans l'étape précédente, vous avez exécuté la production qui a lu le fichier patients.csv et l'a transformé en SDA. Maintenant nous allons faire la même chose avec patients2.csv. Nous pourrions profiter de la production actuelle, mais je voudrais montrer comment créer tout à partir de zéro. Donc, arrêtez cette production, et faisons ce qui suit.

1.    Allez au portail de gestion (http://localhost:52775/csp/sys/%25CSP.Portal.Home.zen?$NAMESPACE=USER, assurez-vous que vous êtes dans l'espace de noms de l'utilisateur).
2.    Créer un CSV Mapper pour le fichier patients2.csv. Interopérabilité > Build > CSV Record Wizard (Assistant d'enregistrement CSV) :

Remarque : sélectionnez CRLF pour Record Terminator (terminateur d'enregistrement)

3.    Cliquez sur "Create RecordMap" pour ouvrir l'interface utilisateur de Record Mapper et modifiez le nom de la classe cible en customsda.Patients2RecordMap.Record :

4.    Sélectionnez BIRTHPLACE et définissez MAXLEN=200 dans le champ Paramètres du type de données. Par défaut, tous les champs %String contiennent 50 caractères, mais BIRTHPLACE et ADDRESS ont besoin de plus d'espace. Faites de même pour le champ ADDRESS :

5.    Cliquez sur le bouton "Save" (Enregistrer) et sur le bouton "Generate" (Générer). Acceptez les options par défaut et cliquez sur Ok pour générer les classes RecordMap.

6.    Cliquez sur "Interoperability" (Interopérabilité) pour passer aux tâches suivantes:

Créer la transformation de données de Custom à SDA

Il est temps d'utiliser le DTL pour construire visuellement la carte de transformation de Custom à SDA.

1.    Cliquez sur Interoperability" > Build > Data Transformations (transformation de données) > Go :

2.    Vous pouvez voir le Data Transformation Builder ici. Cliquez sur le bouton "New" (Nouveau) :

3.    Dans Data Transformation Wizard (Assistant de transformation des données), changez le Package en customsda, et le Name en PatientDTL2 :

4.    À ce stade, nous allons définir la classe de la source. Cliquez sur l'icône de la loupe près du champ "Source Class" :

5.    Cliquez sur Message Classes > customsda > Patients2RecordMap > Record :

6.    À ce stade, la classe "Source Class" devrait ressembler à ceci :

7.    Dans la section Target Type, sélectionnez XML et acceptez Target Class avec la valeur EnsLib.EDI.XML.Document :

8.    Sélectionnez l'icône de la loupe près du Type de document cible et cliquez sur Document XML > SDA3_schema > Container :

Remarque 1 : Le conteneur est l'élément racine de tous les éléments SDA, comme Patient.

Remarque 2 : pour que SDA3_schema soit disponible, les actions suivantes sont nécessaires :
Copier SDA3_schema.xsd dans votre système de fichiers local :

Importez le schéma XSD de SDA3 :

9.    Maintenant, lorsque la source et la cible sont configurées, cliquez sur le bouton OK :

10.    Les champs source et cible sont maintenant disponibles pour le mappage visuel :

11.    Pour créer une transformation, vous devez faire glisser le cercle du champ source et le déposer dans la flèche du champ cible, ligne par ligne.

12.    Dans la section Actions, vous pouvez voir les résultats obtenus :

13.    Après avoir mappé tous les champs, votre liste d'actions ressemblera à ceci :

Remarque : pour les propriétés avec (), vous devez définir l'index car ces propriétés peuvent avoir plus d'un élément. Dans cet exemple, nous n'avons qu'une seule adresse, donc target.{Patient.Addresses(1)….} est configuré avec 1.

14.    Cliquez sur le bouton "Save" (enregistrer) et sur le bouton "Compile" (compiler).

15.    Enfin, cliquez sur le raccourci "Interoperability" pour accéder au menu d'Interoperability :

Créer la production de l'interopérabilité (Interoperability Production), le dernier artefact pour compléter notre travail !

Les productions sont les mécanismes utilisés pour automatiser efficacement les flux d'intégration. Il est temps de créer notre production pour transformer les données des patients du fichier patients2.csv en SDA.

1.    Cliquez sur Interoperability > List > Productions :

2.    Cliquez sur le bouton "New" :

3.    Définissez Customsda sur Package, Patients2Production sur Production Name et Production Type sur Generic. Cliquez sur Ok :

4.    Nous avons maintenant la configuration de production :

5.    Cliquez sur le bouton "Plus" près de "Services" :

Remarque : Les services sont les composants utilisés par les productions pour obtenir des données sources.

6.    Configurez la classe "Service Class" avec la valeur EnsLib.RecordMap.Service.FileService, et le nom du service "Service Name" comme PatientCSVService, et cochez "Enable Now" :

7.    Sélectionnez PatientCSVService et configurez l'onglet Paramètres avec les valeurs

  et cliquez sur "Apply" (appliquer):
●    Chemin du fichier : /opt/user/data/
●    Spécification du fichier : patients2.csv
●    Carte d'enregistrement : Patients2RecordMap
●    Noms des configurations cibles : PatientProcess

8.    Cliquez sur le bouton "Plus" situé près des Opérations :

Remarque : Les opérations sont des composants de production utilisés pour écrire/persister des données sur une cible (bases de données, systèmes, API, services Web, FTP, fichier, etc.)

9.    Configurez l'Opération avec les valeurs suivantes :
●    Classe d'Opération : EnsLib.EDI.XML.Operation.FileOperation
●    Nom d'Opération : PatientSDAOperation
●    Cochez Enable Now

10.    Sélectionnez PatientSDAOperation et définissez la valeur /opt/user/data/ comme chemin de fichier, puis cliquez sur le bouton "Apply" :

11.    Cliquez sur le bouton "Plus" à côté de "Processes" (Processus) :

Remarque : les processus sont le composant de production permettant de coordonner le flux de données.

12.    Configurez le processus métier avec les valeurs suivantes :
●    Classe du processus métier: EnsLib.MsgRouter.RoutingEngine
●    Nom de règle de routage : customsda.PatientRouterRule2
●    Nom du processus métier: PatientProcess
●    Cochez Enable Now

13.    Jusqu'à présent, nous avons créé tous les composants :

14.    Sélectionnez PatientProcess et allez à l'onglet "Settings" > icône de loupe près de "Business Rule Name" (Nom de règle de routage) :

15.    Maintenant, nous allons configurer la règle de routage "Routing Rule" dans l'éditeur de règles "Rule Editor" :

16.    Faites un double-clic sur le composant de contrainte et configurez la Source avec PatientCSVService et la Classe de message avec customsda.Patients2RecordMap.Record :

17.    Actuellement, nous avons configuré la source et la cible :

18.    Sélectionnez le composant de règle et cliquez sur le bouton "Green Plus" :

19.    Sélectionnez Send (Envoyer) pour créer le composant When (Quand) :

20.    Sélectionnez le composant "When", cliquez sur le bouton "Green Plus", puis sélectionnez le composant "Send" :

21.    Vous êtes censé voir l'image affichée ci-dessous sur votre écran :

22.    Faites un double-clic sur le composant cible et définissez les éléments de configuration sur PatientSDAOperation, puis cliquez sur le bouton OK :

23.    Faites un double-clic sur le composant de transformation et définissez "Transforms" sur customsda.PatientDTL2, puis cliquez sur OK :

24.    Maintenant, vous avez vos définitions de règles prêtes :

25.    Cliquez sur le bouton "Save" et allez au menu "Interoperability" :

26.    Allez à Interoperability > List > Productions :

27.    Sélectionnez Patients2Production et cliquez sur le bouton "Open" :

28.    Nous allons lancer notre nouvelle production ! Cliquez sur le bouton "Start" :

29.    Sélectionnez PatentProcess et allez à l'onglet "Messages" pour voir les résultats (messages) :

30.    Cliquez sur un message pour voir un diagramme de séquence "Sequence Diagram" avec les résultats de la transformation :

Comme vous pouvez le constater, il s'agit d'un processus de glisser-déposer facile et entièrement visuel, qui transforme les messages personnalisés en SDA ou en d'autres formats. Pour en savoir plus, consultez les liens ci-dessous :

1.    Création d'intégrations FHIR de base avec InterSystems IRIS for Health : https://learning.intersystems.com/course/view.php?id=1959&ssoPass=1
2.    Découvrez HealthShare pour les développeurs et les intégrateurs de systèmes : https://learning.intersystems.com/course/view.php?id=26&ssoPass=1
3.    Création d'intégrations métier avec InterSystems IRIS https://learning.intersystems.com/course/view.php?id=1437&ssoPass=1
4.    Création d'intégrations de base HL7 avec InterSystems: https://learning.intersystems.com/course/view.php?id=1350&ssoPass=1

0
0 138
Article Lorenzo Scalese · Déc 9, 2022 3m read

Une production simple qui permet de charger des paquets de transactions FHIR dans le serveur FHIR® d'InterSystems® via Box et Dropbox.&nbsp ; En utilisant les composants de connexion MFT inclus et un processus personnalisé Custom Business Process de 14 lignes, cette production traitera vos paquets de transactions vers les ressources FHIR pour une consommation immédiate à la manière magique digne d'Harry Potter.  Idéal pour les Hackathons, la recherche et les cocktails FHIR®.

Tout d'abord, je vous propose une brève visite vidéo de la production, des connexions MFT et de la configuration de l'application Oauth2 pour Box et Dropbox sur IRIS. Ensuite, je vous propose quelques étapes pour vous aider à utiliser le Fournisseur de MFT de votre choix et le flux de travail de votre choix (Desktop, API ou Web Console glisser-déposer).


<iframe width="560" height="315" src="https://www.youtube.com/embed/8q4frFgDpY0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

Quelques gaffes :

  • Les rappels OAUTH2 Call Backs nécessitent des Points d'extrémité SSL pour qu'IRIS fournisse la redirection... le mieux est de tenter le coup sur Health Connect Cloud !
  • Dropbox pour les entreprises a des difficultés avec les jetons basés sur l'équipe, mais Dropbox personnel fonctionne bien. Ce n'est pas un problème, mais cela demande un peu plus.
  • Faites attention au "/" de l'URL de base de Dropbox lorsque vous configurez les connexions MFT (assurez-vous qu'il existe).
  • Les adaptateurs MFT sortants doivent avoir un "/" de fin de ligne pour les chemins d'accès à Box et DropBox.

Maintenant, étant donné que la performance exceptionnelle du contenu alimenté par OBS n'a peut-être pas été à la hauteur, voici les étapes à suivre si la Documentation d'InterSytems ne suffit pas.

Présentation des étapes :

  • Créez l'application FHIRDrop ou FHIRBox à un point, puis STOP ! (Collaborez et écoutez)
  • Configurez les connexions MFT sur votre serveur FHIR InterSystems, HealthConnect ou I4H.
  • Complétez votre application FHIRDrop ou FHIRBox, en fournissant l'url de redirection de la connexion MFT.
  • Autorisez vos connexions MFT.
  • Créez votre production.
  • Lâchez-la comme si c'était chaud ! 
  

Création de l'application FHIRDrop ou FHIRBox

L'idée ici est de "démarrer" la configuration de votre application dans chacune des consoles Box et Dropbox Developer, ce qui vous permet de révéler l'identifiant et le secret du client, puis de laisser l'onglet en suspens et de passer aux connexions IRIS MFT.

   

 

 

(Collaborez et écoutez)
Rassemblez votre identifiant et votre secret client, fermez l'onglet du navigateur et passez à la suite :

Configurez la ou les connexions MFT

L'URL de base : https://api.box.com/2.0

 

L'URL de base : https://api.dropboxapi.com/2/ (attention à la barre de fraction de fin)

 

L'enregistrement complet de l'application

Maintenant, retournez à l'enregistrement de l'application et complétez l'App.&nbsp ; Assurez-vous de brancher l'URL de redirection de l'étape ci-dessus, et ajoutez les paramètres qui ont quelque chose à faire avec file.read, file.write.

  

Autorisation de vos connexions de transfert de fichiers gérées

Revenez à vos connexions de transfert de fichiers gérées et "autorisez" vos connexions en invoquant "Get Access Token".

  

Création de votre production

Production

La source pour les processus opérationnels personnalisés, la production est ici : https://gitlab.com/isc_cloud/fhir-drop-fhir-box-mft-2-fhir

Lâchez-la comme si c'était chaud !

  


Et maintenant, obtenez FHIR !

![image](/sites/default/files/inline/images/gar.png)
0
0 79
Article Lorenzo Scalese · Déc 7, 2022 9m read

Salut la communauté,

J’aimerais profiter de notre sujet sur la capture pour les Entrepôts de Données de Santé (EDS) pour vous présenter comment créer rapidement des clients HTTP SOAP et REST.  IRIS ainsi que des applications disponibles sur Open Exchange proposent des solutions permettant de les générer à partir d’un WSDL ou d’une spécification swagger.

Client SOAP

Pour créer un client SOAP, rien de plus simple, vous avez juste besoin du WSDL.  Un assistant est disponible depuis le Studio IRIS,  il permet de générer vos classes pour un client web service, mais également les business services et business operations si vous souhaitez le consommer avec le framework d'interopérabilité.

0
0 141
Article Guillaume Rongier · Déc 5, 2022 15m read

FTP ( Protocole de transfert de fichiers) est un protocole de réseau permettant de transmettre des fichiers sur des connexions TCP/IP dans un réseau (y compris l'Internet) configuré pour transférer des fichiers via ce protocole. Dans une transaction FTP, un expéditeur de fichiers est appelé hôte local. Un récepteur de fichiers impliqué dans le FTP est un hôte distant, et il s'agit généralement d'un serveur. Bien que de nombreux transferts de fichiers puissent être effectués à l'aide du protocole HTTP (Hypertext Transfer Protocol), le FTP est encore couramment utilisé pour transférer des fichiers en coulisse pour d'autres applications, comme les services bancaires. Par conséquent, nous pouvons dire que FTP est une excellente option pour promouvoir l'interopérabilité basée sur les fichiers entre des systèmes situés dans le même réseau local ou dans l'Internet (un serveur FTP est accessible via l'Internet). Cette interopérabilité peut être enrichie, traitée et orchestrée par le système d'interopérabilité IRIS Interoperability. Pour comprendre comment IRIS peut aider, il est crucial de comprendre la fonctionnalité de l'Architecture d'Interopérabilité IRIS pour FTP, centrée sur les adaptateurs FTP d'entrée et de sortie.

Adaptateur FTP d'entrée

Selon la documentation InterSystems, l'EnsLib.FTP.InboundAdapter permet à InterSystems IRIS de recevoir des fichiers via le protocole FTP. L'adaptateur reçoit une entrée FTP à partir de l'emplacement configuré, la lit et l'envoie sous forme de flux au service métier associé. Le service métier créé et configuré par vos soins utilise ce flux et communique avec le reste de la production. La figure suivante montre le flux global des messages entrants (à l'exclusion des réponses) :

Diagramme d'un fichier FTP circulant de l'extérieur de la production à travers un adaptateur d'entrée FTP et un service métier

En détail :

  1. Chaque fois que l'adaptateur rencontre une entrée provenant de sa source de données configurée, il appelle la méthode interne ProcessInput() de la classe de service métier, en passant le flux comme argument d'entrée.
  2. Celle-ci est exécutée par la méthode interne ProcessInput() de la classe de service métier. Cette méthode effectue des tâches de production de base liées à la gestion des informations internes d'une manière requise par tous les services métier. Il n'est pas nécessaire de personnaliser ou de remplacer la méthode héritée par votre classe de service métier.
  3. La méthode ProcessInput() appelle ensuite votre méthode OnProcessInput() personnalisée, en transmettant l'objet Stream en tant qu'entrée. Maintenant, avec le Stream, il est possible de développer les règles requises par le métier pour les fichiers reçus.
  4. Le message de réponse suit le même chemin mais en sens inverse.

Adaptateur FTP de sortie

Selon la documentation d'InterSystems (https://docs.intersystems.com/iris20221/csp/docbook/DocBook.UI.Page.cls?KEY=EFTP_outbound#EFTP_outbound_default_behavior), l'adaptateur FTP de sortie EnsLib.FTP.OutboundAdapter permet à la production d'envoyer des fichiers via le protocole FTP. Pour utiliser cet adaptateur, vous devez créer et configurer une opération métier spécialement conçue pour ce dernier. Cette opération métier recevra alors un message de la production, recherchera le type de message et exécutera la méthode appropriée. Cette méthode exécute généralement des règles pour générer des fichiers avec le contenu et le format requis par le métier à envoyer à une application.

Scénarios d'utilisation FTP les plus courants pour l'interopérabilité IRIS

Le tableau suivant résume les principaux scénarios d'utilisation de FTP pour l'interopérabilité d'IRIS :

<td>
  Scénario
</td>
<td>
  Réception de lots de données métier dans des fichiers CSV, XML, TXT et JSON.
</td>
<td>
  Envoi des résultats du traitement des données métier par lots en CSV, XML, TXT et JSON à partir des données envoyées précédemment
</td>
<td>
  Processus ETL (extraction, transformation et chargement) de gros fichiers comme parquet, ORC et avro pour les lacs de données Data Lakes et les dépôts de données Data Marts.
</td>
<td>
  Génération de fichiers parquet, ORC et avro à partir des bases de données IRIS pour les envoyer vers les lacs de données Data Lakes et les dépôts de données Data Marts externes.
</td>
<td>
  Consommation asynchrone de messages et de fichiers provenant de systèmes externes
</td>
<td>
  Production de messages et de fichiers asynchrones vers des systèmes externes
</td>
<td>
  Envoi/publication des fichiers générés (rapports PDF, fichiers numérisés, images, etc.) vers les dossiers distants de certains organismes.
</td>
Type d'adaptateur FTP
D'entrée
De sortie
D'entrée
De sortie
D'entrée
De sortie
De sortie

Application modèle

Le modèle IRIS-FTP (https://openexchange.intersystems.com/package/iris-ftp-sample) est un exemple d'utilisation de l'adaptateur FTP ( d'entrée et de sortie).

Production

Ce modèle a une production d'interopérabilité vers :
Recevoir des données CSV à l'aide d'un adaptateur FTP d'entrée dans un service mètier LoadCSVFTPBusinessService ; envoyer son contenu à une opération mètier LoadCSVFTPBusinessOperation ; persister le contenu dans une classe persistante à l'aide de CSVgen.
Effectuer un changement de données CDC (Change Data Capture) dans le tableau Paiement en utilisant un adaptateur SQL d'entrée dans une opération métier PaymentSQLBusinessService et envoyer les données du tableau (dans un fichier JSON) à une opération métier SendSQLDataToFTPBusinessOperation pour mettre le fichier JSON dans un serveur FTP.

Vous pouvez voir cette production ici :

Production modèle FTP

Installation du modèle

Pour installer le modèle en utilisant ZPM, suivez les étapes suivantes :

  1. Ouvrez l'espace de nommage IRIS Namespace avec l'interopérabilité activée.
  2. Ouvrez le terminal et lancez un appel : USER>zpm "install iris-ftp-sample"

Pour installer le modèle en utilisant Docker, il faut procéder comme suit :

  1. Clone/git tire le repo dans n'importe quel répertoire local :
$ clone git https://github.com/yurimarx/iris-ftp-sample.git
  1. Ouvrez le terminal dans ce répertoire et exécuter :
$ compilation de docker-compose
  1. Lancez le conteneur IRIS avec votre projet :
$ docker-compose up -d

Lancement du modèle

Pour exécuter le modèle, suivez les procédures suivantes :

  1. Créez les informations d'identification pour accéder au serveur FTP (Allez vers Interopérabilité > Configurer > Informations d'identification) :
  • ID : FTPCredentials
  • Nom de l'utilisateur : irisuser
  • Mot de passe : sys

Voici le résultat :

Les informations d'identification pour accéder au serveur FTP.

  1. Ouvrez la production et lancez-la, comme indiqué dans l'image ci-dessous :

Informations d'identification pour accéder au serveur FTP

Envoi d'un fichier à l'aide du client FTP et visualisation des données chargées dans un tableau SQL

  1. Ouvrez un client FTP (j'utilise généralement Filezilla pour le faire) et mettez le fichier input/countries.csv dans le dossier FTP racine :
  • Hôte : localhost
  • Nom de l'utilisateur : irisuser
  • Mot de passe : sys

Ouvrez un client FTP (j'utilise généralement Filezilla pour le faire) et mettez le fichier input/countries.csv dans le dossier FTP racine :

FTP Client

  1. Accédez à System Explorer > SQL et tapez la sélection du pays, de la latitude, de la longitude et du nom SELECT country, latitude, longitude, name FROM dc_irisftpsample.Country. Consultez l'image ci-dessous pour voir à quoi devraient ressembler les données CSV chargées dans le tableau SQL :

Select csv results

Insertion de données dans un tableau et un fichier avec le contenu inséré dans un fichier sur le serveur FTP

  1. Accédez à System Explorer > SQL et tapez les valeurs de paiement (montant payeur, destinataire, date de transaction): insert into dc_irisftpsample.Payment(amount payer, receiver, transactiondate) values(100.0,'Yuri','Fabiana', CURRENT_TIMESTAMP). Vous pouvez voir ici la représentation à l'écran du fichier JSON contenant les données insérées dans le serveur FTP :

Select csv results

En coulisses : le code source

Fichiers et dossiers principaux

Dans le dossier iris-ftp-sample nous trouvons les éléments suivants :

  <td>
    Description
  </td>
</tr>

<tr>
  <td>
    Readme.md
  </td>

  <td>
    Informations sur le modèle et instructions d'installation/utilisation
  </td>
</tr>

<tr>
  <td>
    Module.xml
  </td>

  <td>
    Manifeste d'installation de ZPM
  </td>
</tr>

<tr>
  <td>
    Dockerfile
  </td>

  <td>
    Commandes Docker pour créer un conteneur IRIS d'InterSystems
  </td>
</tr>

<tr>
  <td>
    Docker-compose.yml
  </td>

  <td>
    Commandes pour créer une composition de 2 instances docker : 1 instance docker de serveur FTP et 1 instance docker d'InterSystems IRIS dans le même réseau Docker
  </td>
</tr>

<tr>
  <td>
    Input/countries.csv
  </td>

  <td>
    Fichier modèle à utiliser pour tester le chargement des données par FTP et csvgen avec une production FTP modèle.
  </td>
</tr>

<tr>
  <td>
    src/dc/irisftpsample
  </td>

  <td>
    Le dossier du code source dans le paquet dc.irisftpsample
  </td>
</tr>

<tr>
  <td>
    FTPSampleProduction.cls
  </td>

  <td>
    Le code source de la Production FTP (conteneur permettant d'exécuter des services et des opérations métier à l'aide d'adaptateurs FTP d'entrée et de sortie).
  </td>
</tr>

<tr>
  <td>
    LoadCSVFTPBusinessService.cls
  </td>

  <td>
    Classe ObjectScript qui utilise un adaptateur FTP d'entrée pour recevoir des fichiers CSV et envoyer leur contenu à l'opération LoadCSVFTPBusinessOperation.cls.
  </td>
</tr>

<tr>
  <td>
    LoadCSVFTPBusinessOperation.cls
  </td>

  <td>
    Reçoit le contenu d'un fichier CSV et charge ses données dans un tableau SQL en utilisant CSVgen
  </td>
</tr>

<tr>
  <td>
    SendSQLDataToFTPBusinessOperation.cls
  </td>

  <td>
    Reçoit un fichier JSON avec le contenu du tableau "Paiement" de PaymentSQLBusinessService et envoie ce fichier JSON au serveur FTP.
  </td>
</tr>

<tr>
  <td>
    Payment.cls
  </td>

  <td>
    Classe persistante ( tableau SQL "Paiement") pour les données de paiement persistantes à envoyer au serveur FTP.
  </td>
</tr>
Fichier

Cas d'utilisation modèle 1 : Recevoir un fichier CSV du serveur FTP et charger les données CSV dans un tableau SQL.

Pour ce cas d'utilisation, nous avons la séquence suivante :

Texto Descrição gerada automaticamente

  1. L'adaptateur FTP d'entrée lit le fichier CSV et le supprime du serveur FTP en utilisant ces paramètres :
  • Le Chemin du fichier (File Path) est l'endroit où l'adaptateur FTP se connectera pour trouver les fichiers.
  • La fonction de suppression du serveur (Delete From Server) permet de supprimer le fichier du serveur après sa lecture.
  • File Spec est le modèle qui correspond aux fichiers à lire.
  • L'intervalle d'appel (Call Interval) est l'intervalle du tirage (vérification des nouveaux fichiers).
  • Le serveur FTP est le nom de l'IP du serveur dans le réseau ou l'Internet.
  • Port FTP est le port à connecter
  • Les informations d'identification constituent la référence aux informations d'identification pour la configuration des noms d'utilisateur et des mots de passe.
  • Interface gráfica do usuário, Texto, Aplicativo Descrição gerada automaticamente

    Interface gráfica do usuário, Aplicativo Descrição gerada automaticamente

    1. Envoyez le flux d'un fichier CSV à la méthode OnProcessInput du service LoadCSVFTPBusinessService.

    2. Envoyez le flux d'un fichier CSV dans un message Ens.StreamContainer dans l'opération LoadCSVFTPBusinessOperation.

    Class dc.irisftpsample.LoadCSVFTPBusinessService Extends Ens.BusinessService
    {
     
    Parameter ADAPTER = "EnsLib.FTP.InboundAdapter";
    Method OnProcessInput(pInput As %Stream.Object, pOutput As %RegisteredObject) As %Status
    {
        Set tSC = $$$OK, 
        tSource = pInput.Attributes("Filename"),
        tFileLocation = pInput.Attributes("FTPDir"),
        pInput=##class(Ens.StreamContainer).%New(pInput)
     
        Set tSC = ..SendRequestSync("LoadCSVFTPBusinessOperation", pInput, .pOutput, -1)
        
        Quit tSC
    }
     
    }
    1. Envoyez le flux d'un fichier CSV dans un message Ens.StreamContainer à la méthode LoadCSVIntoTable. L'adaptateur utilise le mappage XData pour déterminer la méthode à appeler pour chaque type de message dans la classe dc.irisftpsample.LoadCSVFTPBusinessOperation :
    
    XData MessageMap
    {
    LoadCSVIntoTable
    }
    1. Envoyez le flux comme un fichier CSV temporaire et appelez la méthode Generate pour placer le fichier CSV dans le tableau SQL dc.irisftpsample.Country.
    Class dc.irisftpsample.LoadCSVFTPBusinessOperation Extends Ens.BusinessOperation
    {
     
    Parameter ADAPTER = "Ens.OutboundAdapter";
    Parameter INVOCATION = "Queue";
    Property Header As %Boolean [ InitialExpression = 1 ];
    Property Delimiter As %String [ InitialExpression = "," ];
    Property Classname As %String(MAXLEN = "");
    Property Prowtype As %String(MAXLEN = "");
    Property GuessTypes As %Boolean [ InitialExpression = 1 ];
    Property Append As %Boolean [ InitialExpression = 1 ];
    Property UseLoadData As %Boolean [ InitialExpression = 1 ];
    Parameter SETTINGS = "Header:Basic,Delimiter:Basic,Classname:Basic,Prowtype:Basic,GuessTypes:Basic,Append:Basic,UseLoadData:Basic";
    Method LoadCSVIntoTable(pInput As Ens.StreamContainer, Output pOutput As Ens.StringResponse) As %Status
    {
        
        Set tSC = $$$OK
        Set pOutput = ##class(Ens.StringResponse).%New()
     
        Try {
            Set tSC = ##class(community.csvgen).StreamToFile(pInput.Stream, .pFile)
            Set tSC = ##class(community.csvgen).Generate(pFile, ..Delimiter, ..Classname, ..Prowtype, ..GuessTypes, ..Append, ..UseLoadData, ..Header)
            Set pOutput.StringValue = "OK"
        } Catch err {
            Set pOutput.StringValue = $System.Status.GetOneErrorText(tSC, 1)
        }
     
        Quit tSC
    }
     
    XData MessageMap
    {
    LoadCSVIntoTable
    }
     
    }
    • Remarque 1 : Le paramètre Adapter est utilisé pour choisir l'adaptateur à utiliser par la Business Operation.
    • Remarque 2 : les paramètres tels que Header, Delimiter, Classname, Prowtype, GuessTypes, Append et UseLoadData sont requis par csvgen et configurés par l'utilisateur de Production car ces paramètres sont référencés dans le paramètre SETTINGS de la section Basic :

    Interface gráfica do usuário, Aplicativo Descrição gerada automaticamente

    Uma imagem contendo Interface gráfica do usuário Descrição gerada automaticamente

    Consultez les détails sur les informations requises par CSVgen ici : https://github.com/evshvarov/csvgen.

     

    Cas d'utilisation modèle 2 : Application de la méthode CDC (Change Data Capture) sur le tableau des paiements en utilisant l'adaptateur SQL d'entrée et en envoyant les données du tableau à une opération métier pour les mettre sur le serveur FTP.

    Pour ce cas d'utilisation, nous avons la séquence suivante :

    Linha do tempo Descrição gerada automaticamente

    1. IRIS effectue une opération CDC dans le tableau "Paiement" et génère un fichier JSON avec le contenu du tableau, en supprimant les données lues. L'adaptateur utilise ces paramètres pour déterminer le tableau et les données à lire :
  • L'intervalle d'appel (Call Interval) : les nouvelles données sont vérifiées en quelques secondes
  • DSN : l'espace de nom si le tableau existe.
  • Target Config Names : le composant de la production qui recevra les données (dans ce cas, SendSQLDataToFTPBusinessOperation).
  • Requête : la commande de sélection pour obtenir les données à lire (dans ce cas, il s'agit de données relative au paiement (montant payeur, destinataire,date de transaction), à savoir SELECT ID, amount, payer, receiver, transactiondate FROM dc_irisftpsample.Payment).
  • Requête de suppression : la commande de suppression utilisée pour supprimer les données lues, si nécessaire (dans ce cas DELETE FROM dc_irisftpsample.Payment). 
  • Nom du champ clé : la clé primaire du tableau.
  • Interface gráfica do usuário, Aplicativo Descrição gerada automaticamente

    Interface gráfica do usuário, Texto, Aplicativo Descrição gerada automaticamente

    1. Envoyez le flux de données au format JSON au PaymentSQLBusinessService.

    2. Envoyer le flux du fichier JSON dans un message Ens.StreamContainer dans l'opération métier SendSQLDataToFTPBusinessOperation.

    3. Envoyez le flux du fichier JSON à l'adaptateur FTP de sortie :

    Class dc.irisftpsample.SendSQLDataToFTPBusinessOperation Extends Ens.BusinessOperation
    {
     
    Parameter ADAPTER = "EnsLib.FTP.OutboundAdapter";
    Property Filename As %String(MAXLEN = 1000);
    Parameter SETTINGS As %String = "Filename";
    Method OnMessage(pRequest As Ens.StreamContainer, Output pResponse As %Persistent) As %Status
    {
      Set tFilename=
      ..Adapter.CreateTimestamp(##class(%File).GetFilename("/tmp/sqltojson"),..Filename)
      Quit ..Adapter.PutStream(tFilename, pRequest.Stream)
    }
     
    }
    • Remarque 1 : Le paramètre ADAPTER définit que l'opération métier utilisera l'adaptateur FTP de sortie.
    • Remarque 2: Le paramètre Filename définit le nom du fichier qui se trouve sur le serveur FTP.
    1. Placez le fichier JSON dans le dossier FTP racine avec le nom SQLTOJSON_YYYY-MM-DD_HH.mm.ss.zzz.json en utilisant les paramètres suivants :
  • Le serveur FTP est le nom de l'IP du serveur dans le réseau ou l'Internet.
  • Port FTP est le port à connecter
  • Les informations d'identification constituent la référence aux informations d'identification pour la configuration du nom d'utilisateur et du mot de passe
  • Le chemin du fichier est l'endroit où l'adaptateur FTP se connectera pour trouver les fichiers
  • Nom du fichier est le modèle du nom du fichier sur le serveur FTP
  • Protocole : FTP ou SFTP (FTP avec certificat SSL) 
  • Utiliser PASV : connexions passives avec le serveur FTP
  • Interface gráfica do usuário, Aplicativo Descrição gerada automaticamente

    Interface gráfica do usuário, Texto, Aplicativo Descrição gerada automaticamente

    Pour en savoir plus

  • Documentation officielle pour les adaptateurs FTP : https://docs.intersystems.com/iris20221/csp/docbook/DocBook.UI.Page.cls?KEY=EFTP
  • Apprentissage officiel en ligne sur la production, les services métiers et les opérations : https://learning.intersystems.com/course/view.php?id=1437
  • Dépôt Git pour CSVGEN : https://github.com/evshvarov/csvgen
  • À propos de FTP : https://www.techtarget.com/searchnetworking/definition/File-Transfer-Protocol-FTP
  • 0
    0 211