PC SOFT

PROFESSIONAL NEWSGROUPS
WINDEVWEBDEV and WINDEV Mobile

Home → WINDEV 2024 → Hsurveille… surveille trop !
Hsurveille… surveille trop !
Started by LM Concept, Sep., 27 2022 3:22 PM - 9 replies
Registered member
351 messages
Popularité : +13 (17 votes)
Posted on September, 27 2022 - 3:22 PM
Un exemple pour expliquer. Une liste d’articles est affichée dans une table depuis une requette.
Dans cette fenêtre j’ai mis un hSurveille afin que si une fiche est modifiée depuis un autre poste alors la liste se met à jour.
HSurveille(gsNomFichier,Refresh,hNumEnrTous, hsAjout + hsModification + hsSuppression)


Et dans le Refresh il y a :
// On arrete de surveiller….
HSurveilleStop(gsNomFichier,Refresh,hNumEnrTous)
// Redefinit les paramètres de la requête au cas ou !
MaRequête..Param1 = SAI_PARAM1
HExécuteRequête(MaRequête)
// Je met à jour la table
TableAffiche(TAB_LISTE, taCourantEnreg)
// Réactivation de la surveillance
HSurveille(gsNomFichier,Refresh,hNumEnrTous, hsAjout + hsModification + hsSuppression)


Tout fonctionne bien s’il y a une modification d’une fiche.
Le problème c’est si 50 fiches différentes sont modifiées en même temps. Exemple une requête de modification.
La liste va alors se mettre à jour à chaque modification donc 50 fois !
Je pensais qu’en arrêtant la surveillance cela allait réinitialiser celle-ci. Mais il semble qu’il y ai un "spool" des modifications.
La question est-il possible de réinitialiser ce « Spool » ?
J'ai ce soucis depuis le passage à WD27 ... en 25 je n'avait pas la problème.

Merci à vous
BON DEV
Message modified, September, 27 2022 - 3:24 PM
Registered member
287 messages
Popularité : +51 (79 votes)
Posted on September, 27 2022 - 4:22 PM
Hello, j'utilise HSurveille un peu partout dans mon application et pour éviter ce genre de problème je ne reéxecute pas la requête, je procède manuellement

Voici la façon dont je code ma procédure de callback
SELON TypeModification
CAS hsAjout
// Après avoir lu l'enregistrement avec le numéro d'enregistrement
// si j'ai des critères de sélection et que l'enregistrement ajouté doit être affiché dans ma liste je l'ajoute moi-même dans la table

CAS hsModification
// Après avoir lu l'enregistrement avec le numéro d'enregistrement
// 2 cas de figures
// 1 : l'enregistrement ne figure pas dans la liste, je vérifie s'il répond aux critères de sélection pour être affiché
// 2 : l'enregistrement figure dans la liste, je vérifie s'il répond toujours aux critères de sélection, si oui, je modifie la ligne dans liste
// sinon je supprime la ligne

CAS hsSuppression
// Après avoir lu l'enregistrement avec le numéro d'enregistrement
// s'il est présent dans la liste je supprime la ligne
FIN


Cette façon de procéder est limite instantanée et te fera gagner et économiser de grosse ressources

Petite précision mes listes sont chargés en mémoire (dans la description de la table cocher "chargé en mémoire" et non "Accès direct")

--
#DKR
Message modified, September, 27 2022 - 4:23 PM
Registered member
351 messages
Popularité : +13 (17 votes)
Posted on September, 27 2022 - 6:17 PM
Bonjour,
Merci pour cette réponse.
C'est en effet malin. Mais dans ce cas la table ne correspond plus à la requête !?
Si on supprime une ligne dans la table la requête contient toujours la ligne.
Si on a un parcours de la requête dans la fenêtre cela ne va pas être cohérent avec la liste affichée.

Mais je vais quand même regarder cette solution.

BON DEV
Registered member
386 messages
Popularité : +13 (13 votes)
Posted on September, 28 2022 - 10:31 AM
Bonjour,

Une autre piste serait de s'inspirer des technos du web, où ce genre de cas arrivent assez régulièrement (par exemple, pour afficher des résultats de recherche dès qu'on tape un caractère sans pour autant plomber le serveur de requêtes). Notamment ce qu'on appelle communément "debounce" ou "throttle".

Un article pas trop mal fait avec du code en Javascript se trouve ici :
http://www.kevinsubileau.fr/informatique/boite-a-code/php-html-css/javascript-debounce-throttle-reduire-appels-fonction.html

Dans le cas du HSurveille la fonction Multitache() est interdite alors le throttle semble plus simple à mettre en place :
// A mettre en variable globale à la fenêtre ou au projet ou n'importe
gdhDernierRefresh est une dateheure = "19000101000000000"

// Procédure appelée par HSurveille
Procedure Refresh()

// Throttler
// -------------------
duIntervalle est une durée = DateHeureSys() - gdhDernierRefresh
SI duIntervalle < 10s ALORS
// Si ça fait moins de 10s que la table a été actualisée, on ne fait rien
RETOUR
FIN
// Sinon on met à jour la table et on stocke la dateheure en cours
gdhDernierRefresh = DateHeureSys()


// Mise à jour de la table
// -------------------
// Redefinit les paramètres de la requête au cas ou !
MaRequête..Param1 = SAI_PARAM1
HExécuteRequête(MaRequête)
// Je met à jour la table
TableAffiche(TAB_LISTE, taCourantEnreg)

FIN
Registered member
287 messages
Popularité : +51 (79 votes)
Posted on September, 28 2022 - 10:47 AM
LM Concept a écrit :
> C'est en effet malin. Mais dans ce cas la table ne correspond plus à la requête !?

Dans mon cas une fois une table chargé je ne touche plus à la requête, du coup je fais les modifs sur la table

Dans ton cas alors en plus de modifier la table, modifie aussi ta requête en utilisant les fonctions H(HLitRecherche pour récupérer l'enregistrement, et Hmodifie)

--
#DKR
Registered member
351 messages
Popularité : +13 (17 votes)
Posted on September, 29 2022 - 11:39 AM
Merci a vous.
J'ai essayé une autre méthode qui semble fonctionner pas mal aussi.
Avec le HVersion.

Dans le Refresh j'ajoute
SI gnMemoVersion = HVersion(gsNomFichier) ALORS RETOUR
// On arrete de surveiller….
HSurveilleStop(gsNomFichier,Refresh,hNumEnrTous)
gnMemoVersion = HVersion(gsNomFichier)


Avec gnMemoVersion en variable globale de la fenêtre.

BON DEV
Registered member
287 messages
Popularité : +51 (79 votes)
Posted on September, 29 2022 - 12:07 PM
à quoi sert ton test de HVersion ? Tu rafraîchis comment tes données finalement ? Manuellement ?

--
#DKR
Registered member
351 messages
Popularité : +13 (17 votes)
Posted on September, 29 2022 - 2:41 PM
404 ERROR a écrit :
à quoi sert ton test de HVersion ? Tu rafraîchis comment tes données finalement ? Manuellement ?

--
#DKR

Par exemple la modification de 50 enregistrement (avec une requête) prend 1 seconde.

La procédure est appelé 50 fois.
Mais la première fois version différente donc le tableAfficehe() s'execute.
Puis lors du deuxième appel (imaginons pour l'exemple que le temps qu'il a eu une seconde de passé) la modification de la table est finie et donc la version n'a plus bougé alors je sort du refresh sans rien faire.

Procedure Refresh(sNomFichier, nNumeroEnr, nAction )

SI gnMemoVersion = HVersion(sNomFichier) ALORS RETOUR
// On arrete de surveiller….
HSurveilleStop(sNomFichier,Refresh,hNumEnrTous)
gnMemoVersion = HVersion(sNomFichier)

// Redefinit les paramètres de la requête au cas ou !
MaRequête..Param1 = SAI_PARAM1
HExécuteRequête(MaRequête)
// Je met à jour la table
TableAffiche(TAB_LISTE, taCourantEnreg)
// Réactivation de la surveillance
HSurveille(sNomFichier,Refresh,hNumEnrTous, hsAjout + hsModification + hsSuppression)


Donc au pire ça rafraichi une fois ou deux même si beaucoup d'enregistrement sont modifiés.

BON DEV
Registered member
487 messages
Popularité : +24 (30 votes)
Posted on September, 29 2022 - 3:57 PM
Salut,
moi, j'utilise plus hsurveille, parfois, ça ne surveillait pas.
j'utilise HEnvoieMessageVersClient et HSurAppelServeur, c'est tres efficace et ca évite les aller retours,
ça fonctionne tres bien avec la partie windev mobile sans conso intempestive de datas.

--
José
Message modified, September, 29 2022 - 3:59 PM
Posted on September, 29 2022 - 8:49 PM
Perso j'utilise un TimerSys de, environ 1s, tout dépend du temps de traitement de tes données.

De cette manière, la pocédure ce lance 1s après avoir été notifié et si un autre enregistrement est modifié à l'intérieur de cette seconde, la procédure est stoppé.
En bref, la procédure va se lancer seulement si une seconde c'est écoulé entre 2 modification.

// on ferme le timer en attente s'il y en a un
FinTimerSys(100)

// on lance un timer qui exécutera la procédure dans 1 seconde
TimerSys(LanceMajDonnees, 1s, 100)

PROCEDURE INTERNE LanceMajDonnees()

soit t = TâcheParallèleExécute(ExecutionDeLaRequete, (), tpoCopieDifféréeContexteHFSQL)

TâcheParallèleExécuteAprès(t, AfficheDonnees, (), tpoThreadPrincipal)

FIN

PROCEDURE INTERNE ExecutionDeLaRequete()
// Exécution de la requête et remplissage des données de la classe ou de la structure
...
FIN

PROCEDURE INTERNE AfficheDonnees()
// Affichage des données de la classe ou structure à l'écran de l'utilisateur
...
FIN


Je le fais aussi avec des tâches parallèles, ce n'est pas obligatoires mais beaucoup plus fluide pour l'utilisateur.
Je ne bind pas les données sur une requête mais dans une variable globale à la fenêtre (ou de la l'application) (soit une classe ou une structure). De cette façon la tâche "ExecutionDeLaRequete" exécute la requête et remplie les données en mémoire sans que l'utilisateur soit bloquer et quand c'est terminé, la tâche "AfficheDonnee" affiche les données à l'écran.

Je ne sais pas si c'est une bonne manière de faire, mais mes tableaux de bord fonctionne de cette manière et tout tourne très bien. J'ai environ une centaine d'utilisateurs en même temps et chaque utilisateurs ont leur tableau de bord est en live (ou je devrais dire décaler d'une seconde à cause de mon timer :P)