Bonsoir @ilyes Bahlagui ,

L'erreur <FILEFULL> est caractéristique d'un fichier base de données (IRIS.DAT) qui ne dispose plus d'espace libre et qui ne peut plus s'étendre sur le file system.

Cela peut se produire dans les cas suivants : 

  • le disque sur lequel la database est stockée en ne dispose plus d'espace.
  • la database a été paramétrée avec une taille maximum et elle a été atteinte.

Je lis que vous êtes sur une version IRIS Community, je sais qu'il y a une limite au niveau de la taille des bases de données sur cette version gratuite, cela pourrait être aussi la cause du problème si vous avez atteint cette limite.

Selon la documentation officiel, l'ensemble des bases de données ne peut pas dépasser 10GB en community edition.

Pouvez-vous vérifier si vous êtes dans l'un de ces cas de figure ?

Dans le cas ou vous auriez atteint anormalement la limite de 10 Gb pour l'ensemble des base de données, vous pouvez utiliser l'utilitaire :

Do ^%GSIZE

afin d'identifier les globals les plus volumineuses.

Lorenzo.

Merci pour cette article @Matthieu LAURENT 

L'utilisation du parameter LOCATION est une très bonne pratique pour éviter un piège.

Par défaut si ce n'est pas précisé le système enregistre dans la global qui  correspond au nom de la classe en se terminant par un S (ex :  ^User.TestStreamS pour la classe User.TestStream).  Ce n'est pas forcément un problème, mais à l'usage: si quelqu'un fait 

Set obj.Justificatif = ##class(%Stream.GlobalCharacter).%New() 

Le stream se retrouve par défaut dans ^CacheStream ce qui peut devenir un problème si on répète cela avec des streams de différentes classes.

L'utilisation du parameter LOCATION évite cela même dans ce cas de figure.

Bonsoir Julia,

Si vous renvoyez toujours le json avec la liste tPrinter complète, le plus simple serait de faire un clear de la liste et la recharger, ex : 

 

ClassMethod TestUpdate() As %Status
{
	Set tSC = $$$OK
	
	Set json = {
		"NomPoste":"Poste",
		"tPrinter":
		[
			{
				"NomService":"Petite",
				"NomImprimante":"EPFR_12"
			},
			{
				"NomService":"Grande",
				"NomImprimante":"modif"
			}
		]
	}
	
	Set id = 1 
	
	Set tSC = ..UpdatePoste(id, json)
		
	Return tSC
}



ClassMethod UpdatePoste(id As %Integer, json As %DynamicObject) As %Status
{
	Set poste = ##class(Epc.conf.poste).%OpenId(id, , .tSC)
	
	If $$$ISERR(tSC) Return tSC
	
	Do poste.tPrinter.Clear() ; supprime le contenu actuel de la liste tPrinter
	
	Do poste.%JSONImport(json)
	
	Set tSC = poste.%Save()
		
	Return tSC
}

Est-ce que cela peut vous aider ?

Bonjour @Pierre LaFay , je profite de cet article pour partagé un problème que nous avons tout récemment rencontré.  le paramètre MAXLEN comme ci-dessous: 

Property PropertyName As %String (MAXLEN = "");

signifie "pas de limite", c'est à dire la longueur max d'une chaine.

Via le JDBC, ce MAXLEN="" ne semble pas interprété comme en ObjectScript, vous pouvez donc aussi avoir des données tronquées.  Dans ce cas d'utilisation, il vaut mieux utiliser un MAXLEN avec une grande valeur (ex : MAXLEN = 3000000) que "".  Il s'agit probablement que d'un petit bug au niveau du driver, j'ouvrirai peut être un WRC à ce sujet prochainement.

Merci pour cette notification @Adeline Icard ,

Je viens juste de finir une série de mise à jour en version 2023.1.3 😅

Je ne sais pas dans quelle mesure nous pourrions être exposé à cette memory leak et vais conseiller d'attendre une version 2023.1.4 pour les systèmes de production dans l'attente d'en savoir plus.

Edit: Comme c'est limité à AIX, pas d'impact de mon coté.

Merci pour la traduction de cet intéressant article.

J'en profite pour partager ici mon extrait de code que j'utilise souvent comme base pour le SQL Dynamic:

    Set sc = $$$OK
    
    Set sql = "" ; put your sql query

    Set args($Increment(args)) = ""
    ;Set args($Increment(args)) = ""
    ;Set args($Increment(args)) = ""
    

    Set tStatement = ##class(%SQL.Statement).%New()
    ; Set tStatement.%SelectMode = 2    

    #Dim tRes As %SQL.StatementResult = ##class(%SQL.Statement).%ExecDirect(.tStatement, sql, args...)
    If tRes.%SQLCODE < 0 Return $$$ERROR($$$SQLError, tRes.%SQLCODE, tRes.%Message)

    While tRes.%Next(.sc) {
        Quit:$$$ISERR(sc)

        /// do something
    }

    If $$$ISERR(sc) Return sc

Bonjour @Pierre LaFay ,

Avec plaisir!

Pour le OnLogin, je n'ai pas essayé, mais pour le OnEndRequest j'ai tenté le coup et ce fut un échec :D

Malgré que le OnEndRequest soit bien exécuté, j'ai l'impression qu'il est "asynchrone" ou plutôt qu'il est exécuté après que la réponse soit envoyée au client.  Donc même si on fait Hang dans le OnEndRequest, c'est déjà trop tard malheureusement.

N'hésite pas à partager tes découvertes :)

Bonjour @Pierre LaFay ,

Effectivement comme l'a mentionné @Sylvain Guilbaud IAM t'offrira pas mal de fonctionnalité.

Toutefois si tu veux juste forcer un "Hang 1" lors du login, tu peux t'en sortir une sous classe de %CSP.SessionEvents, ex:

Class dc.pierre.RestEvents Extends %CSP.SessionEvents
{

ClassMethod OnStartRequest() As %Status
{
	#dim %request As %CSP.Request
	Set ^dc.pierre("OnStartRequest", "LastRequest") = $ZDT($Horolog, 3, 1) _ " " _ %request.URL
	Set loginURL = "/login"
	If $Extract(%request.URL, * - $Length(loginURL) + 1, *) = loginURL {	; Vérifie si l'url se termine par /login
		Hang 1
	}
	
	Quit $$$OK
}

}

Il faut alors configurer l'application Web pour utiliser cette classe d'évènements.

Cela peut se paramétrer via le portail admin gestion de la sécurité -> Application Web, ex : 

Lorenzo.

Salut @Cyril Grosjean 
 

Ce n'est pas mon domaine d'expertise, mais je suppose que le processus utilise le framework d'interoperabilité en mode synchrone et qu'une transaction (TSTART) est encore ouverte avant l'appel au business service.

Lorsque cette situation se produit, le système effectue automatiquement un TCOMMIT.

Tu peux tenter vérifier cela en plaçant une ligne de debug $TLEVEL (cette variable spécial donne le niveau de transaction courant ou 0 si pas de transaction).

Lorenzo.

Merci @Pierre LaFay .

Content que tu as pu trouver une solution :)

Le mapping même avec le namespace %ALL permet de sélectionner exactement ce que tu souhaites mettre à disposition des autres namespaces (donc pas forcément tout ce qui est dans une DB, une sélection peut être effectuée).  Je souligne ce point juste au cas ou cela te serait utile à l'avenir.

Lorenzo.

Bonjour @Pierre LaFay

Oui, il est possible de faire du mapping, mais il faut bien distinguer deux choses:

  1. Package mapping Celui-ci permet de rendre accessible des package d'un namespace à un autre.   Dans le cas d'une classe %Persistent, il faut bien comprendre que seul le code sera mappé. En ce qui concerne les données enregistrée cela nous amène au 2ème point.  
  2. Global Mapping Il permet de rentre accessible les données de vos globals à votre namespace en spécifiant la base de données source.

Ces configurations peuvent s'effectuer par programmation ou plus simplement via le portail d'administration au niveau de la configuration du namespace (voici le lien de la doc officiel si cela peut vous être utile).

Dans le cas qui vous occupe peut être qu'il serait plus simple d'effectuer la requête SQL directement dans "RemoveIrisTestUsers" étant donné que vous faites déjà le changement de namespace.

Toutefois, pour un package de classe utilitaire comme "Bna.Utils" peut être que vous pourriez le mapper sur le namespace %ALL.

Le namespace %ALL, est spécial, les packages (ou les globals et routines) qui y sont mappées sont automatiquement accessible pour tous les autres namespace.  Donc le code : 

Set sc = ##class(Bna.Utils.Sql).SelectFirstColsInArray(query, .userIds)

Pourra être exécuter même si vous venez de faire un Set $Namespace = "%SYS".

Si besoin, je peux vous fournir une réponse plus complète avec des captures d'écran concernant la configuration avec %ALL.

Lorenzo.

Bonjour @Cyril Grosjean ,

Je ne sais pas si ça peut vous aider mais il existe la possibilité d'enregistrer les credentials

Il a très longtemps, j'ai déjà utilisé cela pour stocker login/password pour des requêtes http basic auth.

Je dois avouer que je ne sais plus exactement comment ça fonctionne, mais c'est peut être une piste.

Le point de menu est disponible dans "Interoperability -> Configurer -> Droits"

Je n'ai pas le lien dans la documentation, mais saviez-vous que : 

USER>!ping www.google.com
 
 
Pinging www.google.com [142.251.36.4] with 32 bytes of data:
Reply from 142.251.36.4: bytes=32 time=12ms TTL=110
Reply from 142.251.36.4: bytes=32 time=11ms TTL=110
Reply from 142.251.36.4: bytes=32 time=11ms TTL=110
Reply from 142.251.36.4: bytes=32 time=12ms TTL=110
 
Ping statistics for 142.251.36.4:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 11ms, Maximum = 12ms, Average = 11ms

ou encore : 

USER>!echo "hello world"
 
"hello world"
USER>