Rendus fusionnés dans Import Supervisor : Adapters lancés en simultanés

Bonjour,

Après constatation, lorsque plusieurs adapteurs sont exécutés en parallèle/simultané, leurs rendus dans Import Superviser sont fusionnés.

Un exemple concret pour illustrer mes propos

Par exemple, le fichier log se présente sous cette forme :

2022-03-30 03:30:04,856 INFO Start adapter: AdapterNUMERO1
2022-03-30 03:30:04,856 INFO User: system
2022-03-30 03:30:04,856 INFO Date: Wed Mar 30 03:30:04 CEST 2022

… ( Log du preProcess / processLine / postProcess des adapteurs AdapterNUMERO1 AdapterNUMERO2 AdapterNUMERO3 ) …

2022-03-30 03:30:02,168 INFO Start adapter: AdapterNUMERO2
2022-03-30 03:30:02,168 INFO User: system
2022-03-30 03:30:02,168 INFO Date: Wed Mar 30 03:30:02 CEST 2022

… ( Log du preProcess / processLine / postProcess des adapteurs AdapterNUMERO1 AdapterNUMERO2 AdapterNUMERO3 ) …

2022-03-30 03:30:04,563 INFO Start adapter: AdapterNUMERO3
2022-03-30 03:30:04,563 INFO User: system
2022-03-30 03:30:04,563 INFO Date: Wed Mar 30 03:30:04 CEST 2022

… ( Log du preProcess / processLine / postProcess des adapteurs AdapterNUMERO1 AdapterNUMERO2 AdapterNUMERO3 ) …

(idem pour le fichier source, error, et log)

Bien que je n’ai constater ce problème que maintenant… en réalité en remontant les précédents import dans import superviser, nous avons rencontré ce cas plusieurs fois dans le passé jusqu’à même le 05/11/2021 (pour être précis) donc certainement que ce problème existait bien avant.

C’est comme si la construction de ces rendus d’import supervisor n’étaient pas indépendant les unes des autres. (J’aurais tendance à dire qu’il faudrait instancier (de manière unique) la génération de ces rendus, mais je ne m’avancerais pas plus étant donné que je n’y ai pas la main :slight_smile: )

Étant donné le nombre relativement important d’imports que nous faisons, avoir ces infos (pour de l’analyse par exemple) nous est indispensable.

Questions :

  • Est-ce de ma faute ? (problème de paramétrage ?)
  • Est-ce que cela relève du socle de Simplicité ?
  • Avez vous déjà rencontré ce problème ?

Bonus : Health check

[Platform]
Status=OK
Version=5.1.34
BuiltOn=2022-03-08 22:43

Bien cordialement,

Mounir

Bonjour,

Nous allons essayer de reproduire votre cas, pour cela nous avons besoin d’informations complémentaires :

  • de quel type d’adaptateurs parle-t-on ? Java ? Si oui qui héritent de quel classe helper ? Font ils usage du singleton Grant.getAdminSystem() si oui de quelle manière ? etc.
  • comment sont lancés ces imports via adaptateurs ? manuellement ? via des actions planifiées dans des tâches cron (si oui merci de nous fournir le code de ces actions et de nous dire quel(s) users executent ces actions) ?
  • Etc.

Bonjour,

  1. Effectivement on parle ici d’adaptateurs Java héritant de LineBasedAdapter ou com.simplicite.util.integration.CSVLineBasedAdapter.
    On ne fait pas appel à “Grant.getAdminSystem()” mais à “Grant.getSystemAdmin()” pour :
  • Exécuter des requêtes (
    - return Grant.getSystemAdmin().simpleQuery("…");
    - return Grant.getSystemAdmin().query("…"); )
  • Instancier des ObjectDB (
    • ObjectDB Objet1 = Grant.getSystemAdmin().getObject(“nom_instance1”,“objet_metier1”);
    • ObjectDB Objet2 = Grant.getSystemAdmin().getTmpObject(“nom_instance2”,“objet_metier2”); )
  • Logger des infos ( AppLog.info(“info…”, Grant.getSystemAdmin()); )
  1. Ces imports sont lancés automatiquement via des actions planifiées dans les crons depuis des fichiers présent sur le cloud GCP.
    Voici les différentes méthodes utilisées en partant du code de l’action, jusqu’à la dernière méthode d’import (qui pourrait être celle qui est intéressant)
   
// ---- LA METHODE LIEE L'ACTION

public String actionImportDPR18(){
	// verification de la présence du fichier du jour avec delta
	String query ="select f.row_id, mla_delta_name from mla_file_input f inner join mla_input_flow_board fb on fb.row_id=mla_mlafileinput_mlainputflowboard_id where fb.mla_idq_idf = 'DPR18RBP' and f.created_dt>=CURRENT_DATE and mla_start_process is null;";
	String[] res = getGrant().querySingleRow(query);
	if(Tool.isEmpty(res)){
		return "no process";
	}else{
		//recupération des param +  lancement de l'import
		try{
			importOneFileById(res[0]);
		}catch(Exception e){
			return "erreur d'intégration : " + e.getMessage();	
		}
		return "import ok";	
	}
}

// ----- LA METHODE importOneFileById

public String importOneFileById(String rowId)  throws Exception 
{
	AppLog.info("START id " + rowId, getGrant());
	MlaFileInput fileInput = (MlaFileInput) getGrant().getTmpObject("MlaFileInput");
	boolean[] initAccess = getGrant().changeAccess("MlaFileInput", false,true,true,false);
	try{
		fileInput.resetFilters();
		fileInput.setFieldFilter("row_id",rowId);
		
		List<String[]> r = fileInput.search();
		for(String[] s : r) {
			fileInput.setValues(s);
			AppLog.info("fileInput  = "+fileInput.getFieldValue("MLA_FILE_NAME"), getGrant());
			fileInput.traitement();
		}
	}catch(Exception e){
		throw e;
	}
	finally{ 
		getGrant().changeAccess("MlaFileInput", initAccess);
	}
	return "";	
};

// ----

private boolean traitement() throws Exception 
{
	if(findDeltaFile()) return _traitement();
	return false;	
};

private boolean _traitement() throws Exception 
{
	String start_process_date = Tool.getCurrentDateTime();
	String path = getFieldValue("mlaMlafileinputMlainputflowboardId.MlaDeltaFolderOncloud")+getFieldValue("MLA_DELTA_NAME");
	if(!isDelta()) 
		path = getFieldValue("mlaMlafileinputMlainputflowboardId.MlaGeneratefilesFolderOncloud")+getFieldValue("MLA_FILE_NAME");
	try{
		String 	adapter = getFieldValue("mlaMlafileinputMlainputflowboardId.mlaIngestiondatabordAdaptername");
		AppLog.info("getGrant() "+getGrant(), getGrant());
		MlaExchangeFileCloud mlaExchangeFileCloud = new MlaExchangeFileCloud(getGrant());
		if(Tool.isEmpty(adapter))
		{
			setFieldValue("MLA_FILE_INPUT_STATUT",MlaFileInput.STATUT_ADAPTOR_MISSING);
			if(isMandatory()) return true;
		}
		else if("0".equals(Grant.getSystemAdmin().simpleQuery("select COALESCE(count(*),0) from m_adapter where adp_name='"+adapter+"' ")))
		{
			setFieldValue("MLA_FILE_INPUT_STATUT",MlaFileInput.STATUT_ADAPTOR_DONT_EXISTS);
			if(isMandatory()) return true;
		}
		else
		{
			AppLog.info("traitement "+getFieldValue("mlaMlafileinputMlainputflowboardId.MLA_FILE_IDF")+ " recherche le fichier  : "+path, getGrant());
			

			
			InputStream in = mlaExchangeFileCloud.getFileCloud(path);
			if(in != null)
			{
				
				setFieldValue("MLA_FILE_INPUT_STATUT",MlaFileInput.TRAITEMENT_EN_COURS);
				setFieldValue("MLA_START_PROCESS",Tool.getCurrentDateTime());
				if(hasChanged(false)) save();

				boolean isOk = mlaExchangeFileCloud.treatInputStream(adapter,in,path);	

				// on gere les message d'erreur
				if(!isOk)
				{
					setFieldValue("MLA_FILE_INPUT_STATUT",MlaFileInput.STATUT_OK_WITH_REJET);
				} else setFieldValue("MLA_FILE_INPUT_STATUT",MlaFileInput.STATUT_OK);

				setFieldValue("MLA_END_PROCESS",Tool.getCurrentDateTime());

			}else{
				if(!isDelta()) setFieldValue("MLA_FILE_INPUT_STATUT",MlaFileInput.STATUT_FICHIER_NON_ACCESSIBLE);
				else setFieldValue("MLA_FILE_INPUT_STATUT",MlaFileInput.STATUT_WAITING_DELTA);
				if(isMandatory()) return true;							
			}				
			if(hasChanged(false)) save();
		}
	}catch(Exception e){
		setFieldValue("MLA_FILE_INPUT_STATUT",MlaFileInput.STATUT_KO);
		setFieldValue("MLA_END_PROCESS",Tool.getCurrentDateTime());
		if(hasChanged(false)) save();
		if(isMandatory()) return true;	
	}finally
	{
		String sqlXmlId = "select COALESCE(row_id,0) from m_xml where xsp_origin = '"+path+"' and  '"+start_process_date+"' <= created_dt and created_dt <= '"+Tool.getCurrentDateTime(2000)+"'";
		String xmlId = Grant.getSystemAdmin().simpleQuery(sqlXmlId);
		setFieldValue("mlaFileinputXmlId",xmlId);			
		if(hasChanged(false)) save();
	}
	return false;	
};

// ---- LA METHODE QUI FAIT L'IMPORT

public boolean treatInputStream(String adapterName, InputStream in,String origine) throws Exception
{
	Integration integration = new Integration();
	Message r = integration.importADP(Grant.getSystemAdmin(), adapterName, in, origine, null);
	return (r == null);
}

Je reste evidemment disponible pour tout autre information complémentaire au besoin.

Merci d’avance pour l’aide

Utiliser le singleton Grant.getSystemAdmin() dans un contexte d’accès concurrents potentiels nécessite de faire attention à:

  • utiliser des instances d’objet distinctes dans les différents traitements lancés en //
  • et/ou synchroniser les partie de code qui utilisent ce singleton (ce qui pas forcément toujours une bonne chose si on parle de traitement “longs”)

Faut de quoi ce sera potentiellement pas thread safe.

Ce n’est pas un pb pour des accès SQL simples (type query ou simpleQuery) par contre dès qu’on parle d’objets métier il est impératif d’être certain de ne pas utiliser la même instance d’objet en // sinon il peut se passer n’importe quoi. Une bonne pratique dans des adapters s’executant potentiellement en // c’est donc d’utiliser des noms d’instance distincts dans les différents adapters.

Les tâches cron qui lancent les traitements sont des tâches cron internes à Simplicité ? Si oui elles sont associées à quel utilisateur ?

Je pose la question car, de manière générale, ce n’est pas une bonne pratique d’utiliser le singleton Grant.getSystemAdmin() quand l’utilisateur courant (getGrant()) dispose des droits qui vont bien. Ca ne dispense pas bien sûr de s’assurer de ne pas utiliser en // les mêmes instances d’objet associées à ce user.

Utiliser Grant.getSystemAdin() est un pattern à réserver aux cas où on veut ponctuellement faire une action avec les droits du super user system (qui a les mêmes droits que ceux paramétrés pour le user designer) quand le user courant ne dispose pas des droits requis pour cette opération (l’autre approche consistant à donner temporairement les droits ad hoc au user courant).

PS: A notre niveau, nous allons vérifier si la partie écriture de la supervision d’import proprement dite en fin de traitement ne pose pas de pb thread safe, de mémoire c’est bien synchronisé à ce niveau mais on ne sait jamais…

1 Like

Bonjour,

Pour contextualiser, ces adapteurs que nous utilisons ont pour vocation d’être (et le sont déjà en majorité) lancés automatiquement
(d’où l’usage du singleton Grant.getSystemAdmin() à outrance)

En ce qui concernant nos objets, ils sont bels et biens instanciés de manière distinctes (je reproduis le bug assez facilement pour étudier la chose)

Je reproduis le bug aussi sans passer par les CRONS donc je doute qu’ils soient fautifs mais ils associées à l’utilisatieur “designer”

En revanche peut être que le soucis proviens de notre manière d’exécuter l’import… en effet pour reproduire ça nous utilisons la méthode importADP de la manière suivante :

→ importADP(Grant.getSystemAdmin(), adapterName, inputStream, null, null);

doc : Integration

Et c’est peut être l’endroit où ce fameux singletonGrant.getSystemAdmin()” pose problème ?

Si vos tâches CRON sont associées au user designer il n’y a aucune raison fonctionnelle d’utiliser le singleton Grant.getSystemAdmin() car le getGrant() de l’adapter aura les mêmes droits.

L’avantage d’utiliser le getGrant() de l’adapter vs le singleton c’est d’être dans le contexte d’un grant indépendant pour chacune des tâches cron et du coup il n’y a plus de risques de traitements non thread safe.

PS: Dans un contexte où ça aurait du sens d’utiliser le le singleton (ex: si vous lancez une tâche cron avec un user qui a moins de droits au sein de laquelle vous avez ponctuellement besoin de privilèges supplémentaires) il faut alors faire appel à lui dans des blocs synchronized (sachant que l’autre approche quand on a besoin de droits supplémentaires c’est plutôt de les donner temporairement au grant courant)

1 Like

Hello @david

Je reviens sur le sujet pour te donner quelques infos/précisions :slight_smile:

1 - Le remplacement des Grant.getSystemAdmin() par getGrant() n’y fait rien, on constate toujours la même anomalie
2 - On utilise bien des instances d’objets distincts, ex :

public String preProcess() {
pdsLevel = getGrant().getObject(“adp_16”, “MlaPdsLevel”);
pdsLevelT = new BusinessObjectTool(pdsLevel);
pdsPackage = getGrant().getObject(“adp_16”, “MlaPdsPackage”);
pdsPackageT = new BusinessObjectTool(pdsPackage);

N.B. : On constate également ce pb avec des adapteurs qui n’initialisent même pas d’objets

Avez vous d’autres pistes ?

P.S. : En espaçant le moment d’exécution des deux adapteurs de plusieurs secondes, je constate qu’il n’y a pas de fusion de logs.
Je pense qu’une solution (un peu débrouillardise je l’admet) pour l’instant, pourrait être de modifier les expressions cron pour espacer le lancement de nos adapteurs de qlqs dizaines de secondes… Mais évidemment il serait meilleur de réellement comprendre ce pb…

Cdlt,

Mounir

OK on va essayer de reproduire.

Avez vous bien constaté ce pb sur une révision à jour (5.1.43 sur la branche de maintenance 5.1 ou 5.2.2 sur la branche release actuelle) ?

Bonne question, nous avons (sur tout nos env) actuellement la version 5.1.34 :slight_smile:

Il y a eu largement plus d’une centaine de commits sur la branche 5.1 depuis la révision 5.1.34. Donc ça vaudrait le coup de vous assurer que le pb est bien toujours présent sur la révision à jour.

En tout état de cause nous ne pouvons investiguer que sur cette révision à jour et s’il y a un correctif à fournir ce sera livré dans le cadre d’une nouvelle révision.

Il n’y a objectivement aucune bonne raison de ne pas suivre les révisions que nous poussons, notamment si vous sollicitez notre support (cf. le template des demandes de support où nous vous demandons de confirmer que le pb que vous nous remontez est bien présent sur la révision à jour)

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.