Retours tests Remote object et DataLink 5.3.0-beta

Bonjour,

j’initie ce fil pour lister les bugs (ou problèmes) rencontrés dans le cadre de l’évaluation de la beta de la 5.3.0…

Petit problème de prise en compte de la propriété clé fonctionnelle définie au niveau de l’attribut et pas reprise au niveau de l’attribut d’objet…

Je me répond à moi-même : après un clear cache l’alerte disparaît et l’ObjectField est bien considéré comme “clé fonctionnelle” de l’objet.

Si je comprends bien le dispositif de synchronisation master/slave, la seule fonction qui permet de diffuser depuis un master vers un slave est la fonction synchronize. Cette fonction doir être instanciée sur le slave qui va pull les données disponibles sur le master à partir d’une date de référence dite “date de dernière mise à jour” (ou date de dernière synchro).

  • Je crée plusieurs records sur le master
  • J’actionne la synchronisation sur le slave en mettant la date de dernière synchro dans le passé
  • Les records créés sur le master sont bien reportés sur le slave
  • J’ajoute un record sur le master
  • J’actionne la synchronisation sur le slave en mettant la date/heure de la synchro précédente
    → Tous les records précédemment synchronisés sont supprimés et seul le dernier record créé postérieurement à la synchro précédente est reporté sur le slave.

Soit je n’ai pas compris comment ça doit fonctionner soit il y a un loup…

Bonsoir, avez-vous une documentation plus détaillée de la mise en oeuvre des DataLinks que ce qui est dans la release notes 5.3 ?
Ce mécanisme est très (très) intéressant et nous bâtissons d’ores et déjà des plans sur son usage.

Effectivement les supports ne sont pas à jour. On va l’inclure.

En attendant et en résumé :

  • Il faut modéliser les objets à data-linker dans un module à installer chez toutes les applications qui s’en serviront,
  • Il faut leur mettre l’option “timestamp” car besoin de la date de dernière mise à jour entre bases,
  • Chaque application peut hériter de ses objets localement (dans un autre module métier) pour les surcharger / ajouter d’autres champs non synchronisés,
  • Dans un autre module de config, il faut déclarer tous les Hosts avec leurs credentials API/REST qui sont habilités à ces objets en CRUD
  • Définir des DataLinks en spécifiant quels hosts sont maitres/esclaves (tout le monde peut être maître, mais il ne peut pas y avoir que des esclaves) et quels objets sont à synchroniser dans un ordre donné de dépendances

Au runtime :

  • Vue d’une application, ces objets sont comme des objets locaux / table locale / jointure…
  • On voit les datalinks se charger au clear-cache dans les logs
  • En cas de mise à jour UI, les maitres appellent tous les hosts de façon synchrone (pour garantir l’ordre des éventuels appels successifs) via la couche API classique (le service “sync” est comme un POST mais qui force le même row_id partout)
  • En cas d’arrêt d’un host ou d’erreur HTTP en heure ouvrée, une tache cron “DataLink” resynchronise en masse les tables à partir du dernier passage/timestamp en base par objet _SYNC_MASTER_<object> pour ne pas refaire un full-scan. Tous les objets ayant été modifiés depuis cette date sont resynchronisés. Supprimer ces paramètres = full synchro
  • Au pire si tout est arrêté ou que les bases sont devenues trop lourdes à synchroniser par la couche API/REST, il est possible de copier les tables via d’autres mécanismes rapide/DB, il y a stricte égalité des row_id (faut juste faire gaffe aux colonnes ajoutées localement).

Limitation actuelle :

  • on ne peut pas spécifier quels champs sont à synchroniser, c’est tout l’objet qui est synchronisé (d’où le design pattern de faire des héritiers)
  • il y aura surement des cas indéterminés de flux qui se croisent s’il y a plusieurs maitres en parallèle qui autorisent la mise à jour concurrente, le système ne posera pas de verrou entre application (la table m_object_usage reste pour une concurrence d’accès local pour le moment).

Une doc a été ajoutée en dessous de celle des remote objects.

https://docs.simplicite.io/documentation/05-remote/simplicite.md

Il manque encore le support de formation / docs2 et quelques copies d’écran, mais rien de bien compliqué quand on a compris les grands principes.

Ce serait également un bon exemple d’ajouter également au Simpli-store un exemple de datalink sur la démo qui serait abonnée aux “fournisseurs + produits” mis à jour dans une application de gestion des stocks.

1 Like

Merci beaucoup François pour ces éléments.
Je ne comprends toujours pas où ça coince…

Lorsque je procède à une full synchro (sur le slave) avec une date antérieure à l’initialisation dans le master, tout est synchronisé dans le slave → ici je comprends que c’est bien le comportement attendu.

Mais lorsque je réactive la tâche cron (sur le slave) qui s’appuie sur la date de dernière synchro (cf. étape précédente), toutes les lignes ayant un timestamp antérieur à la dernière synchro sont supprimées et seules les lignes modifiées (dans le master) postérieurement à la synchro sont conservées et mises à jour (dans le slave) → là je pense que ce n’est pas ce qui est attendu ou alors je n’ai pas compris le concept…

Bizarre effectivement, le cas de la suppression me laisse perplexe… on doit avoir traité ça pas un annule et remplace qui en fait un peu trop…
on regarde.

L’algo de synchro en masse se passe en 2 temps :

  • boucle sur le pages des records distants (master) depuis la dernière date de scan D
    synchro de chaque record (updated_by >= D) avec coloriage des rowId traités (créés ou modifiés)
  • boucle sur les records en local (slave) depuis cette date pour suppression des non coloriés = supprimé dans le master s’il ne les avait pas envoyé

Le filtre sur la date est surement inopérant, et ça supprime trop loin dans le passé. On va renforcer le filtre qui pourtant est une search-spec sur le champ updated_by.

Ok merci!
Par contre je ne saisi pas pourquoi le updated_by est pris en compte lors de la synchronisation… quel est le usecase ? Seuls les records modifiés par un user en particulier seraient synchronisés ?

Autre question : quels sont les triggers de resynchro autres que le cron ou le clear cache ?

erreur de ma part, on parle bien de “update_dt” uniquement.
on va renforcer la boucle qui cherche les lignes à détruire, le filtre peut effectivement sauter lors de la pagination (hooks, resetFilters…).

  • les resynchro en masse sont par cron en utilisant la date de dernier scan

  • ou via l’action sur le datalink qui permet de forcer la date de début de scan via UI

  • sinon la synchro unitaire se fait lors de chaque save/delete.

1 Like

Bug reproduit, même en renforçant les filtres pour ne pas supprimer les records suite à une resynchro depuis une certaine date. La tache cron fait un peu trop le ménage.
On va analyser ça de plus près.

UPDATE : tache cron DataLink

Problème d’arrondi corrigé: le scan (qui démarre à T1) cherchait à tord de la date de dernier passage T0, alors qu’on doit chercher à T0+1 seconde, et à la fin si pas d’erreur on dit que T1 devient la date de dernier passage T0. Les records qui se trouvaient sur la ligne T0 après 1 premier full-scan se faisait massacrer, ça ne se produira plus :

  • Les 4 champs timestamp seront désormais synchronisés pour éviter les jeux de carte mélangés ou que tous les TS locaux soient ceux du batch
  • L’algo optimise toujours les suppressions par coloriage des records qui existent en local mais non trouvés sur la période dans un master. Un dernier “GET= 404” est fait vers le master pour être sûr qu’il n’existe plus avant suppression locale.

Merci pour les fix… Je teste un nouveau cas:

  1. création d’un nouveau record sur le master → création reportée sur le slave (OK)
  2. mise à jour du record sur le master → mise à jour reportée sur le slave (OK)
  3. suppression du record sur le master → rien n’est fait sur le slave

Est-ce le comportement attendu / une limite du dispositif ?

Mon besoin serait que si le slave est en capacité de s’aligner sur le master (i.e. aucune règle du modèle métier n’interdit la suppression du record dans le modèle du slave) la suppression soit opérée. Sinon (suppression interdite) on laisse le record en place sur le slave avec idéalement un event “DESYNCHRO” tracé sur le record en question (cf. log EVENT/level ERROR dans les opérations du slave).

Bonjour Bruno,

  • Les suppressions sont bien propagées de façon synchrone MASTER=>SLAVE / push
  • ou faites plus tard via la cron du SLAVE si inaccessible (arrêté / timeout http…) / pull

Ca ne doit pas fonctionner dans le vieux mode de suppression qui ne passe pas par les hooks
(si DELETE_CHILD_HOOK=no). On ne l’utilise plus car ça n’applique pas les règles de delete cascade.

Dans la version qui arrive :

  • on a ajouté des traces dans les logs car on était un peu dans le noir sur la partie appels synchrones
  • corrigé un bug dans le helper APITool sur les recherches paginées
  • et réaligné les timestamps entre les bases / le pull supprime trop de lignes non trouvées à tord

A restester quand on aura rebuildé les images 5.3 car ça corrige peut-être ton cas.

En cas d’erreur de suppresssion côté slave il y aura une trace :
AppLog.error("syncData: delete error " + err + " on object " + uk, null, null);
Et côté Master, il y aura aussi des traces qui signalent les appels “sync” vers un slave.

Si la suppression est toujours KO, il faudra voir plus en détail pourquoi au niveau des droits ou du paramétrage (filtre sql, hook ?). Si c’est côté master ou salve…

1 Like

ok en fait j’ai l’impression qu’aucune mise à jour synchrone entre le master et le slave… je dois avoir un loup dans la conf…

Partage ton paramétrage de DataLink

  • Il y a une subtilité sur le nom qu’on donne au host pour qu’un serveur se reconnaisse comme master au démarrage (cf doc: application name ou SERVER_URL…)
  • Vérifier les URL + credentials + service API ouverts

https://docs.simplicite.io/documentation/05-remote/simplicite.md

Attention la 5.3.0-beta n’a pas été rebuildée depuis le 23/09, un build est prévu ce soir

<?xml version="1.0" encoding="UTF-8"?>
<simplicite xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.simplicite.fr/base" xsi:schemaLocation="http://www.simplicite.fr/base https://www.simplicite.io/resources/schemas/base.xsd">
<object>
	<name>DataLinkHost</name>
	<action>upsert</action>
	<data>
		<dlh_name>bcsimaster</dlh_name>
		<row_module_id.mdl_name>BCSIDataLink_EnterpriseArchitecture</row_module_id.mdl_name>
		<dlh_url>https://bcsibeta.renault.simplicite.io</dlh_url>
		<dlh_user>services</dlh_user>
		<dlh_pwd>xxx</dlh_pwd>
	</data>
</object>
<object>
	<name>DataLinkHost</name>
	<action>upsert</action>
	<data>
		<dlh_name>bcsimsea</dlh_name>
		<row_module_id.mdl_name>BCSIDataLink_EnterpriseArchitecture</row_module_id.mdl_name>
		<dlh_url>https://bcsibetamsea.renault.simplicite.io</dlh_url>
		<dlh_user>services</dlh_user>
		<dlh_pwd>xxx</dlh_pwd>
	</data>
</object>
<object>
	<name>DataLinkHosts</name>
	<action>upsert</action>
	<data>
		<dlk_link_id.dlk_name>Interface microservice EA - MDM</dlk_link_id.dlk_name>
		<dlk_host_id.dlh_name>bcsimaster</dlk_host_id.dlh_name>
		<dlk_type>M</dlk_type>
		<row_module_id.mdl_name>BCSIDataLink_EnterpriseArchitecture</row_module_id.mdl_name>
	</data>
</object>
<object>
	<name>DataLinkHosts</name>
	<action>upsert</action>
	<data>
		<dlk_link_id.dlk_name>Interface microservice EA - MDM</dlk_link_id.dlk_name>
		<dlk_host_id.dlh_name>bcsimsea</dlk_host_id.dlh_name>
		<dlk_type>S</dlk_type>
		<row_module_id.mdl_name>BCSIDataLink_EnterpriseArchitecture</row_module_id.mdl_name>
	</data>
</object>
</simplicite>

Je pense que c’est là que le bât blesse…