Ok, effectivement, les choses semblent avoir changées.

D'apres la doc kong : https://docs.konghq.com/gateway/latest/kong-manager/auth/super-admin/#cr...

Lors de la migration de kong, tu dois passer le paramètre : KONG_PASSWORD

Activer le RBAC : KONG_ENFORCE_RBAC: 'on'

Et te connecter avec :

Login : kong_admin et Mot de passe : Celui spécifié dans la migration

Après tu dois avoir accès au bouton Invite Admin

effectivement, il y a un problem de lock avec SQLAlchmy et embedded python.

ce que tu proposes, c'est de passer d'une connexion SQLAlchmy avec EmbeddedPython vers une connexion classique sur TCP/IP.

Pourquoi cela ne fonctionnerait pas en production ?

Tu as à variabiliser les login et mot de passe et le tour est joué.

L'adresse du server ne doit pas changer, ca sera toujours localhost dans ton cas.

Bonjour,

C'est la connexion sqlalchemy qui creer une transaction qui n'est jamais relâchée, le code suivant devrait fonctionner:

ClassMethod creerFichierCSV(
	query As %String,
	filename As %String) [ Language = python ]
{
    import pandas as pd
    from sqlalchemy import create_engine,text
    engine = create_engine('iris+emb:///')
    try:
        df = pd.read_sql(text("SELECT * from Ens_Util.Log"),engine)
    except Exception as e:
        raise e
    finally:
        engine.dispose()

    df.to_csv("toto", index=False, header = True, encoding='utf-8', sep =';')

    return
}

Pour relâcher la transaction, aller dans :

Puis selection la transaction :

et enfin, la terminer :

Je ne sais pas si VsCode support cette fonctionnalité, ce pendant, il est tout à fait possible d'ouvrir un ticket pour en faire une demande :

https://github.com/intersystems-community/vscode-objectscript/issues

J'imagine que ces propriétés sont liées aux objects projects qui aident aux déploiements.

Pour accéder aux options de projets il faut monter un dossier isfs qui fait la passerelle entre iris et vscode :

https://docs.intersystems.com/components/csp/docbook/DocBook.UI.Page.cls...

Bonjour,

Je rencontre aussi ce problème, c'est lié à la version 2023.1 d'iris et pas à VsCode. La redirection des erreurs dans la sortie standard ne se fait pas systématiquement.

C'est résolu à partir de la 2023.3.

Un workaround :

Do $system.OBJ.SetQualifiers("/multicompile=0",1)

Cette commande désactive la compilation parallèle dans tout le système. Cela ne pose pas de problème si des classes individuelles sont compilées. Par contre, elle est plus lente pour de nombreuses classes. Mais vous pouvez le réactiver en utilisant le CompileFlag /multicompile=1 si vous devez compiler beaucoup de classes à la fois :

do $SYSTEM.OBJ.Compile("Demo.Demo","/multicompile=1",.err)

Salut Cyril,

La méthode PutStream() prend un objet %Stream d'IRIS en paramètre. Il faut donc que tu convertisses ton fichier en %Stream avant de l'envoyer.

Exemple :

XMessage

from grongier.pex import Message
from dataclasses import dataclass

@dataclass
class XMessage(Message):
    StringStream: str
    BinaryStream: bytes

BusinessOperation

from grongier.pex import BusinessOperation
from datetime import datetime
from X.xImport import XMessage
import iris

class XArticleExport(BusinessOperation):
    def get_adapter_type():
        return "EnsLib.FTP.OutboundAdapter"

    def on_init(self):
        return super().on_init()

    def on_message(self, request: XMessage):
        if hasattr(request, "Stream"):
            # Préparation du stream
            stream = iris.cls("%Stream.GlobalCharacter")._New()
            source = ""
            # Si le stream est en string on l'utilise tel quel
            if request.StringStream:
                source = request.StringStream
            elif request.BinaryStream:
                source = request.BinaryStream.decode("utf-8")

            # On écrit le contenu du fichier dans le stream
            n = 4092
            chunks = [source[i:i+n] for i in range(0, len(source), n)]
            for chunk in chunks:
                stream.Write(chunk)

            filename = "exportArticles_" + datetime.now().strftime("%Y%m%d") + ".csv"
            esc: int = self.Adapter.PutStream(filename, stream)
            if esc == 1:
                self.log_info("File imported successfully with code : " + esc)
        else:
            self.log_error("Pas de stream reçu ! Code: " + esc)
        return super().on_message(request)

Si tu peux changer de namespace quand tu le souhaites pour ca deux facons :

  • avant d'executer iop tu changes la variable d'environnement IRISNAMESPACE.
export IRISNAMESPACE=TEST
iop -m path/to/my_settings.py
  • dans ton fichier my_settings.py tu peux changer le namespace avec la fonction suivante :
import iris
# switch namespace to the TEST namespace
iris.system.Process.SetNamespace("TEST")

# print the current namespace
print(iris.system.Process.NameSpace())

from TEST.bo import MyBo

CLASSES = {
    "MyIRIS.MyBo": MyBo
}

PRODUCTIONS = [
    {
        "MyIRIS.Production": {
            "@TestingEnable": "true",
            "@Name": "MyIRIS.Production",
            "Item": [
                {
                    "@Name": "Instance.Of.MyBo",
                    "@ClassName": "MyIRIS.MyBo",
                }
            ]
        }
    }
]

humm, ne pas confondre la PWG (Private WebGateway) et la WebGateway.

La private webgateway est un mini apache qui est embarqué dans iris.
Il n'a pas a etre configuré.

De plus, dans la configue pour acceder à ce portail il ne faut pas oublier d'ajouter ton ip en white list

System_Manager=*.*.*.*

Pourquoi souhaites-tu le configurer ?

Bonjour,

Effectivement, le service EnsLib.SQL.Service.GenericService est un service de type "Business Service" qui va générer un message pour chaque ligne de résultat de la requête SQL. Ce service est donc adapté pour des requêtes qui retournent un nombre limité de lignes.

Je pense que tu vas devoir passer par du code custom.

Voici un exemple en Python qui est relativement simple à mettre en oeuvre.

Le bs :

from grongier.pex import BusinessService
import pandas as pd
from sqlalchemy import create_engine


from .msg import SQLMessage

class SQLService(BusinessService):

    def __init__(self, **kwargs):
        self.sql = None
        self.conn = None
        self.target = None

    def on_init(self):
        if not hasattr(self, 'sql'):
            raise Exception('Missing sql attribute')
        if not hasattr(self, 'conn'):
            raise Exception('Missing conn attribute')
        if not hasattr(self, 'target'):
            raise Exception('Missing target attribute')

        self.engine = create_engine(self.conn)

        # raise an error if cannot connect to the database
        self.engine.connect()

    def get_adapter_type():
        """
        Name of the registred Adapter
        """
        return "Ens.InboundAdapter"

    def on_process_input(self, message_input):
        # create a dataframe from the sql query
        df = pd.read_sql(self.sql, self.engine)
        # create a message
        message = SQLMessage(dataframe=df)
        # send the message to the target
        self.send_request_sync(self.target, message)
        return

Ici on utilise la force de pandas pour créer un dataframe à partir du résultat de la requête SQL. On crée ensuite un message qui contient le dataframe et on l'envoie au target.

La configuration est faite à partir de propriétés suivantes :

  • sql : la requête SQL
  • conn : la connexion à la base de données
  • target : le target

Le message :

from grongier.pex import Message
from dataclasses import dataclass
from pandas.core.frame import DataFrame

@dataclass
class SQLMessage(Message):
    dataframe: DataFrame = None

Le message qui contient le dataframe.

La target qui permet de créer le fichier csv :

from grongier.pex import BusinessOperation
from .msg import SQLMessage

import pandas as pd

class CSVOperation(BusinessOperation):

    def __init__(self, **kwargs):
        self.filename = None

    def on_init(self):
        if not hasattr(self, 'filename'):
            raise Exception('Missing filename attribute')

    def on_sql_message(self, message_input: SQLMessage):
        # get the dataframe from the message
        df = message_input.dataframe
        # create a csv file
        df.to_csv(self.filename, index=False)
        return

La configuration est faite à partir du fichier settings.py :

from sqltocsv import bo,bs
import os

CLASSES = {
    'Python.Bs.SQLService': bs.SQLService,
    'Python.Bo.CSVOperation': bo.CSVOperation
}

db_user = os.environ.get('POSTGRES_USER', 'DemoData')
db_password = os.environ.get('POSTGRES_PASSWORD', 'DemoData')
db_host = os.environ.get('POSTGRES_HOST', 'db')
db_port = os.environ.get('POSTGRES_PORT', '5432')
db_name = os.environ.get('POSTGRES_DB', 'DemoData')

PRODUCTIONS = [{
    "Python.Production": {
        "@Name": "Python.Production",
        "@LogGeneralTraceEvents": "false",
        "Description": "",
        "ActorPoolSize": "2",
        "Item": [
            {
                "@Name": "Python.Bs.SQLService",
                "@Category": "",
                "@ClassName": "Python.Bs.SQLService",
                "@PoolSize": "1",
                "@Enabled": "true",
                "@Foreground": "false",
                "@Comment": "",
                "@LogTraceEvents": "false",
                "@Schedule": "",
                "Setting": {
                    "@Target": "Host",
                    "@Name": "%settings",
                    "#text": "sql=select * from formation\nconn=postgresql://"+db_user+":"+db_password+"@"+db_host+":"+db_port+"/"+db_name+"\ntarget=Python.Bo.CSVOperation"
                }
            },
            {
                "@Name": "Python.Bo.CSVOperation",
                "@Category": "",
                "@ClassName": "Python.Bo.CSVOperation",
                "@PoolSize": "1",
                "@Enabled": "true",
                "@Foreground": "false",
                "@Comment": "",
                "@LogTraceEvents": "false",
                "@Schedule": "",
                "Setting": {
                    "@Target": "Host",
                    "@Name": "%settings",
                    "#text": "filename=/tmp/export.csv"
                }
            }
        ]
    }
}]

On utilise les variables d'environnement pour la connexion à la base de données.

Tu as l'exemple complet ici :

https://github.com/grongierisc/formation-template-python/tree/demo_sqltodb

Je laisse un autre membre de la communauté répondre avec une solution en ObjectScript.

Bonjour,

Les versions LTS d'iris sont les versions en XXXX.1.

Nous appelons ces versions des Extended Maintenance (EM)

Les versions qui ne finissent pas par un 1 sont des Continus Delivery

Plus d'information sur ce post :

https://community.intersystems.com/post/updates-our-release-cadence

Ici pour suivre toutes les versions publiées ainsi que les releases notes:

https://docs.intersystems.com/iris.html