Réponse d' @Eduard Lebedyuk :
L'approche la plus sûre consiste à utiliser Privileged Routine Application.
- Se connecter pour publier des commentaires
Réponse d' @Eduard Lebedyuk :
L'approche la plus sûre consiste à utiliser Privileged Routine Application.
Ajouté au portail des idées InterSystems
Bonjour @Jean-Charles.Cano,
pour en savoir plus sur les logs, côté IRIS tu peux activer les traces dans les paramètres du Business Service :.png)
En t'assurant que les traces sont aussi activées au niveau des paramètres de la production :.png)
merci @Vadim Aniskin pour ce retour.
Merci @Pierre LaFay et @Seisuke Nakahashi pour cet article intéressant, qui apporte une autre méthode d'exploitation des rapports de performances.
Je vous invite à essayer également YASPE (Yet Another System Performance Extractor), qui génére des rapports html par une exploitation des rapports en Python.
Hello @Pierre LaFay
tu peux aussi utiliser la commande "!" sans paramètre pour ouvrir une session du système d'exploitation et revenir au terminal IRIS en quittant la session de l'OS.
Exemple ci-dessous :
.png)
La commande alias est aussi très pratique et souvent méconnue :
.png)
Merci @Iryna Mykhailova et @Brett Saviano
Cela est très utile en effet et fonctionne aussi avec IRIS 2023.3 sans Private Web Server (depuis IRIS 2023.2)
.png)
Bonjour @Pierre LaFay
pour rediriger la sortie standard du Terminal IRIS, tu peux ouvrir un fichier et l'indiquer via la commande USE
Exemple ci-dessous et en ligne :
Class utils.file
{
Parameter DIRECTORY = "/data/";Parameter FILENAME = "results";Parameter EXTENSION = ".txt";/// Redirect standard output to a fileClassMethod results() As%Status
{
set sc = $$$OKSET file=..#DIRECTORY _ ..#FILENAME _ "_" _ $tr($zdt($h,8)," :")_..#EXTENSION
OPEN file:("NRW"):5USE file
WRITE !,"BEGIN RESULTS ",$zdt($h,3),!
do##class(UnitTest.utils).run("Test3")
WRITE !,"END RESULTS ",$zdt($h,3)
CLOSE file
WRITE !,"Results are in ",file,!
return sc
}
}
.png)
Avec le fichier contenant toutes les écritures vers la sortie :.png)
Bonjour @Cyril Grosjean
le pb vient peut-être des librairies python requises qui n'ont pas été correctement installées sur l'environnement WIndows.
Tu peux essayer de le résoudre en installant les librairies python sur Windows via la commande irispip
C:\InterSystems\IRIS\bin>irispip install --target C:\InterSystems\IRIS\mgr\python iris-pex-embedded-pythonBonjour @Cyril Grosjean
l'erreur indique un "accès refusé".
Peux-tu donner plus d'information sur le code du BP PostFusionIntervention ?
Bonjour @Cyril Grosjean
essaie d'utiliser embedded python, en remplaçant la connexion par create_engine('iris+emb:///'):
from sqlalchemy import create_engine
_engine = create_engine('iris+emb:///')
Bonjour @Cyril Grosjean
essaie d'utiliser embedded python, en remplaçant la connexion par create_engine('iris+emb:///'):
from sqlalchemy import create_engine
_engine = create_engine('iris+emb:///')Cool 😀
Merci pour le message de confirmation.
Bonjour @Jean-Charles.Cano
si ton service FTP ne doit s'exécuter qu'une seule fois par jour, à une heure bien précise, la planification est effectivement le bon moyen, en veillant à ce que l'intervalle entre appel soit supérieur à la durée séparant l'heure du START et celle du STOP.
L'autre moyen, sans planification, est de simplement mettre un intervalle entre appels de 86400 pour obtenir un appel une seule fois par jour. L'inconvénient ici étant que le service restera démarré 24h/24h sans utilité.
Exactement @Jean-Charles.Cano
Je te confirme que tu avais déjà trouvé la bonne solution par toi-même et que tu étais sur la bonne piste 😀
@Jean-Charles.Cano,
une autre approche existe cependant : celle qui consisterait à construire une image Docker contenant ton flux FTP, et à lancer une fois par jour un conteneur de cette image pour exécuter le flux.
La commande "docker run" pouvant elle-même être exécutée via $zf(-100) depuis une tâche planifiée exécutée par IRIS à la fréquence souhaitée.
Si vous souhaitez en savoir plus sur le potentiel du jumeau numérique en Supply Chain développé par SCALE, vous pouvez retrouver leurs coordonnées sur leur page Partner Directory.
NB : SCALE = Supply Chain Agile & LEan
Très bon article ; merci @Luis Angel Pérez Ramos
Pour ceux et celles qui souhaitent prolonger la découverte de FHIR, vous pouvez accéder à sa documentation en ligne.
You're welcome @shan yue
Thanks for your app and your participation in the FHIR contest.
Merci à @Vitaliy Serdtsev : il est aussi possible de récupérer directement un JSON à partir d'une requête SQL, avec les fonctions JSON_ARRAYAGG et JSON_OBJECT :
SELECT JSON_ARRAYAGG(json_obj)
FROM (SELECT TOP 5
JSON_OBJECT(
'Name':name
,'Age':age
,'DOB':to_char(dob,'Day DD Month YYYY')
) json_obj
FROM sample.person
)SELECT JSON_ARRAYAGG(json_obj)
FROM (SELECT JSON_OBJECT(
'Name':name
,'Age':age
,'DOB':to_char(dob,'Day DD Month YYYY')
) json_obj
FROM sample.person
)
WHERE %VID BETWEEN 1 AND 5Résultat :
Bonjour Pierre,
le meilleur moyen de protéger l'API est d'utiliser API Manager (IAM), qui permet de gérer à la fois l'authentification et une limite sur la fréquence d'appels.
Bienvenue à IRIS 2024 !!
Chez un de nos clients, la nouvelle fonctionnalité des bases de données multi-volumes a notamment permis de pallier la contrainte de la taille des fichiers sur leur serveur de stockage en réseau (NAS) limitée à 4To.
.png)
Le portail System > Databases > Database Details permet de voir les différents volumes créés ; ici avec un seuil à 15Mo :
.png)
Extrait de la documentation en ligne :
À mesure que les bases de données clients se développent, les fichiers de bases de données évoluent également. Pour éviter que ces fichiers ne deviennent trop volumineux ou n'atteignent les limites strictes du système de fichiers, InterSystems IRIS prend désormais en charge la division transparente de votre base de données sur plusieurs « volumes » physiques. Cette nouvelle fonctionnalité se configure facilement : pour n'importe quelle base de données, vous pouvez désormais configurer une taille de seuil. Lorsque votre fichier IRIS.DAT initial est sur le point d'atteindre cette taille et que de nouvelles données globales doivent être écrites, InterSystems IRIS créera de manière transparente un nouveau fichier « volume de base de données » et commencera à écrire de nouvelles données dans ce fichier. Lorsque ce volume atteint le seuil, un autre fichier est créé, et ainsi de suite.
Il n'y a aucun impact sur les applications et le code qui accèdent aux données, car ils continuent de voir le contenu complet de la base de données, quel que soit le nombre de volumes sur lesquels elle est répartie. De plus, vous pouvez configurer le répertoire dans lequel le prochain volume doit être créé et, si nécessaire, vous pouvez réorganiser les volumes de base de données dans les répertoires en tant qu'opération de maintenance. Combiné aux travaux prévus pour augmenter la taille maximale globale de la base de données, cela garantira que vos données restent faciles à gérer, bien dans la plage des pétaoctets.
IRIS (de même que Caché|Ensemble) permet en effet l'utilisation de jointures implicites (arrow syntax) en s'appuyant sur le dictionnaire unifié Objet/SQL des classes/tables définies dans ton modèle de données.
Ceci offre l'avantage de simplifier l'écriture de requêtes SQL.
Bonjour @Jean-Charles.Cano
peut-être que tu auras plus de détails en consultant la base de données d'AUDIT :
Système > Gestion de la sécurité > Afficher la bdd d'audit
Notamment sur des Événements d'audit système de type Protect
Exemple en ObjectScript
Include %occErrorsClass MyApp.Account Extends%Persistent
{
Property Balance As%Numeric;/// Deposit money into the account
Method Deposit(amount As%Numeric) As%Status
{
// PreconditionsIf amount < 0 {
Return$$$ERROR($$$GeneralError, "Deposit amount must be non-negative")
}
// Store the old balanceSet oldBalance = ..Balance// Update balanceSet..Balance = oldBalance + amount
// PostconditionsIf (..Balance '= $$$NULLOREF) && (..Balance '= (oldBalance + amount)) {
Return$$$ERROR($$$GeneralError, "Postcondition failed: Balance calculation error")
}
Quit$$$OK
}
/// Withdraw money from the account
Method Withdraw(amount As%Numeric) As%Status
{
// PreconditionsIf amount < 0 {
Return$$$ERROR($$$GeneralError, "Withdrawal amount must be non-negative")
}
If (..Balance = $$$NULLOREF) || (..Balance < amount) {
Return$$$ERROR($$$GeneralError, "Insufficient funds")
}
// Store the old balanceSet oldBalance = ..Balance// Update balanceSet..Balance = oldBalance - amount
// PostconditionsIf (..Balance '= $$$NULLOREF) && (..Balance '= (oldBalance - amount)) {
Return$$$ERROR($$$GeneralError, "Postcondition failed: Balance calculation error")
}
Quit$$$OK
}
/// Invariant: Balance should always be non-negative
Method CheckBalanceInvariant() As%Status
{
Set tSC = $$$OKIf..Balance < 0 {
Set tSC = $$$ERROR($$$GeneralError, "Balance invariant violated: Balance is negative")
}
Quit tSC
}
/// Class method to test the Account classClassMethod TestAccount() As%Status
{
// Create a new instance of AccountSet account = ##class(MyApp.Account).%New()
// Initialize the balanceSet account.Balance = 0// Test depositing a positive amountSet tSC = account.Deposit(100)
If$$$ISERR(tSC) {
Write"Deposit failed: ", $system.Status.GetErrorText(tSC), !
Quit tSC
}
Write"Deposit succeeded: Balance after deposit: ", account.Balance, !
// Test depositing a negative amount (should fail)Set tSC = account.Deposit(-50)
If$$$ISERR(tSC) {
Write"Deposit of negative amount failed as expected: ", $system.Status.GetErrorText(tSC), !
} Else {
Write"Deposit of negative amount unexpectedly succeeded", !
Quit$$$ERROR($$$GeneralError, "Deposit of negative amount unexpectedly succeeded")
}
// Test withdrawing a valid amountSet tSC = account.Withdraw(50)
If$$$ISERR(tSC) {
Write"Withdrawal failed: ", $system.Status.GetErrorText(tSC), !
Quit tSC
}
Write"Withdrawal succeeded: Balance after withdrawal: ", account.Balance, !
// Test withdrawing more than the available balance (should fail)Set tSC = account.Withdraw(200)
If$$$ISERR(tSC) {
Write"Withdrawal of more than available balance failed as expected: ", $system.Status.GetErrorText(tSC), !
} Else {
Write"Withdrawal of more than available balance unexpectedly succeeded", !
Quit$$$ERROR($$$GeneralError, "Withdrawal of more than available balance unexpectedly succeeded")
}
// Check balance invariant (should succeed)Set tSC = account.CheckBalanceInvariant()
If$$$ISERR(tSC) {
Write"Balance invariant violated: ", $system.Status.GetErrorText(tSC), !
Quit tSC
}
Write"Balance invariant holds true", !
// Intentionally set balance to negative value to trigger balance invariant failureSet account.Balance = -10// Check balance invariant (should fail)Set tSC = account.CheckBalanceInvariant()
If$$$ISERR(tSC) {
Write"Balance invariant violated as expected: ", $system.Status.GetErrorText(tSC), !
} Else {
Write"Balance invariant unexpectedly held true", !
Quit$$$ERROR($$$GeneralError, "Balance invariant unexpectedly held true")
}
Write"Account operations completed successfully", !
Quit$$$OK
}
Storage Default
{
<Data name="AccountDefaultData">
<Value name="1">
<Value>%%CLASSNAME</Value>
</Value>
<Value name="2">
<Value>Balance</Value>
</Value>
</Data>
<DataLocation>^MyApp.AccountD</DataLocation>
<DefaultData>AccountDefaultData</DefaultData>
<IdLocation>^MyApp.AccountD</IdLocation>
<IndexLocation>^MyApp.AccountI</IndexLocation>
<StreamLocation>^MyApp.AccountS</StreamLocation>
<Type>%Storage.Persistent</Type>
}
}
Avec le résultat suivant :
write##class(MyApp.Account).TestAccount()
Deposit succeeded: Balance after deposit: 100
Deposit of negative amount failed as expected: ERROR #5001: Deposit amount must be non-negative
Withdrawal succeeded: Balance after withdrawal: 50
Withdrawal of more than available balance failed as expected: ERROR #5001: Insufficient funds
Balance invariant holds true
Balance invariant violated as expected: ERROR #5001: Balance invariant violated: Balance is negative
Account operations completed successfully
1Exemple en Python :
classAccount:def__init__(self):
self.balance = 0defdeposit(self, amount):if amount < 0:
raise ValueError("Deposit amount must be non-negative")
old_balance = self.balance
self.balance += amount
# Postconditionsif self.balance != old_balance + amount:
raise ValueError("Postcondition failed: Balance calculation error")
defwithdraw(self, amount):if amount < 0:
raise ValueError("Withdrawal amount must be non-negative")
if self.balance < amount:
raise ValueError("Insufficient funds")
old_balance = self.balance
self.balance -= amount
# Postconditionsif self.balance != old_balance - amount:
raise ValueError("Postcondition failed: Balance calculation error")
defcheck_balance_invariant(self):if self.balance < 0:
raise ValueError("Balance invariant violated: Balance is negative")
@classmethoddeftest_account(cls):
account = cls()
try:
# Test depositing a positive amount
account.deposit(100)
print("Deposit succeeded: Balance after deposit:", account.balance)
# Test depositing a negative amount (should fail)
account.deposit(-50)
except ValueError as e:
print("Deposit of negative amount failed as expected:", e)
else:
raise ValueError("Deposit of negative amount unexpectedly succeeded")
try:
# Test withdrawing a valid amount
account.withdraw(50)
print("Withdrawal succeeded: Balance after withdrawal:", account.balance)
# Test withdrawing more than the available balance (should fail)
account.withdraw(200)
except ValueError as e:
print("Withdrawal of more than available balance failed as expected:", e)
else:
raise ValueError("Withdrawal of more than available balance unexpectedly succeeded")
try:
# Check balance invariant (should succeed)
account.check_balance_invariant()
print("Balance invariant holds true")
except ValueError as e:
print("Balance invariant violated:", e)
# Intentionally set balance to negative value to trigger balance invariant failure
account.balance = -10try:
# Check balance invariant (should fail)
account.check_balance_invariant()
except ValueError as e:
print("Balance invariant violated as expected:", e)
else:
raise ValueError("Balance invariant unexpectedly held true")
print("Account operations completed successfully")
# Run the test
Account.test_account()