Skip to content

fix(sync): ne plus interrompre la synchronisation sur un équipement ou un hub illisible - #57

Open
jkurz78 wants to merge 2 commits into
jeedom:betafrom
jkurz78:fix/sync-continue-on-error
Open

jkurz78 wants to merge 2 commits into
jeedom:betafrom
jkurz78:fix/sync-continue-on-error

Conversation

@jkurz78

@jkurz78 jkurz78 commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Description

Depuis #52, request() lève une exception quand la réponse du relais n'est pas du JSON valide. C'est une bonne chose : en stable, ce cas renvoyait null sans bruit. Mais dans sync() cette exception n'est pas capturée. Une seule réponse invalide interrompt donc toute la synchronisation.

Cas réel, sur la beta à jour (4d43290), avec deux hubs : la synchro s'arrête vers la fin des 49 équipements du premier hub (000BF237) avec le toast « Réponse JSON invalide pour la requête à Ajax System ». Les derniers équipements, les groupes de ce hub (le correctif #56 ne peut donc pas s'appliquer) et tout le second hub (0014B92D) ne sont pas traités.

Avec le premier commit de cette PR, le log montre enfin la réponse brute :

[request] /user/…/hubs/000BF237/devices/004D189F : Syntax error (42 octets) => Too many requests, please try again later.

La cause est donc la limite de requêtes d'Ajax, et non un équipement particulier. La rafale de sync() (une requête de détail par équipement, espacées de 200 ms) dépasse le quota. À partir de là, toutes les requêtes suivantes échouent : fin du premier hub, groupes, second hub. Cela explique aussi le false renvoyé par /groups pour ce hub dans les logs de #43 : les groupes sont lus en dernier, après tous les équipements.

Changements

  • Limite de requêtes : quand request() reçoit « Too many requests » sur un GET, il fait une pause de 5, 10 puis 15 s avant de renvoyer la requête. Ces nouvelles tentatives ne comptent pas comme des tentatives de renouvellement de session. Au-delà de trois pauses, l'erreur habituelle est levée.
  • Par équipement : la lecture du détail est faite dans un try/catch. En cas d'échec, un warning est logué avec l'identifiant et le nom, puis la synchro passe à l'équipement suivant. L'équipement existant n'est pas modifié.
  • Par hub : le corps de la boucle est déplacé dans syncHub(), appelé dans un try/catch. Une erreur sur un hub (infos, liste des équipements, groupes) n'empêche plus les autres hubs d'être synchronisés.
  • Retour à l'utilisateur : une fois tout traité, sync() lève une exception qui indique le nombre total d'erreurs. Le compteur est passé par référence, pour que les erreurs d'équipements restent comptées si le hub échoue ensuite.
  • Diagnostic : request() écrit en debug le message d'erreur JSON, la taille et les 200 premiers octets de la réponse invalide.

Le diff est surtout un décalage d'indentation dû à l'extraction de syncHub() ; git diff -w montre les lignes réellement modifiées.

Suggested changelog entry

La synchronisation continue malgré un équipement ou un hub illisible, attend et réessaie quand Ajax limite le nombre de requêtes, et trace la réponse invalide dans le log.

Related issues/external references

Types of changes

  • Bug fix

Validation

Quatre tests ajoutés dans tests/groups.php :

  • équipement illisible : les équipements suivants et les groupes des deux hubs sont synchronisés, un warning identifie l'équipement, le début de la réponse est logué et l'erreur est comptée ;
  • groupes illisibles sur un hub après un équipement illisible : l'autre hub est quand même synchronisé, et les deux erreurs sont comptées ;
  • limite de requêtes passagère : les requêtes aboutissent après les pauses et la synchronisation se termine sans erreur ;
  • limite de requêtes persistante : quatre envois au maximum, puis échec signalé sans bloquer le hub suivant.

php -l OK. tests/groups.php : 9/9. tests/session.php : 16/16 en local (PHP 8.5). La CI couvrira 7.4 et 8.3. git diff --check OK.

Testé sur l'installation réelle à deux hubs (49 + 19 équipements) :

  • le premier commit a permis d'identifier la limite de requêtes ;
  • avec le second, la synchronisation va jusqu'au bout : les groupes des deux hubs sont créés ou migrés et le second hub est traité. La limite se déclenche après environ 50 requêtes en 15 s et ne se lève qu'environ une minute après la première requête. Les pauses de 5, 10 puis 15 s ont suffi pour l'équipement suivant, mais pas pour celui qui a atteint la limite (il est logué en warning et compté). Des pauses plus longues, par exemple 10/20/30 s, couvriraient la fenêtre complète.

À noter : avec les pauses, une synchronisation complète d'une grosse installation dépasse une minute. Derrière un reverse proxy dont le délai est de 60 s (cas du proxy Synology par défaut), le navigateur affiche une page d'erreur du proxy alors que la synchronisation continue côté serveur. Lancer la synchronisation en tâche de fond depuis le bouton serait plus robuste ; je laisse ce choix au mainteneur.

🤖 Generated with Claude Code

jkurz78 and others added 2 commits October 21, 2026 20:28
…u un hub illisible

Une réponse non JSON pour un seul équipement levait une exception qui
arrêtait sync() : les équipements suivants, les groupes du hub et les
hubs suivants n'étaient jamais traités.

- chaque équipement est lu dans un try/catch : warning puis équipement suivant ;
- chaque hub est synchronisé dans syncHub(), isolé des autres hubs ;
- une exception finale indique le nombre d'erreurs une fois tout traité ;
- request() trace en debug le début (200 octets) de la réponse invalide.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…quêtes

Le log d'une synchronisation réelle montre que les réponses non JSON
sont un texte brut « Too many requests, please try again later. » :
la rafale de requêtes de sync() dépasse le quota Ajax, et toutes les
requêtes suivantes échouent (fin du premier hub, groupes, second hub).

- request() met en pause 5, 10 puis 15 s avant de renvoyer un GET limité ;
- le compteur d'erreurs de sync() est passé par référence à syncHub()
  pour ne plus perdre les erreurs d'équipements quand le hub échoue ensuite.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant