Archives mensuelles : février 2019

[Win32Service] Comment utiliser les paramètres de Récupération

Vous avez des services Windows écrit en PHP ? Il utilise l’extension Win32Service ? La version 0.4 apporte la gestion des options de récupération des services.

Ces paramètres permettent de définir des actions à réaliser dans le cas ou votre service défaille. Il existe 3 situations et donc 3 actions possibles qui sont :

  1. Action à réaliser lors de la première défaillance
  2. Action à réaliser lors de la seconde défaillance
  3. Action à réaliser lors des défaillances suivantes

Comment le gestionnaire des services compte-t-il les défaillances ?
Une défaillance est comptée si le programme exécuté sort en indiquant au gestionnaire de service un code retour différent de 0 (zéro).

Avant la version 0.4, quelle que soit la raison de la fin de l’exécution de PHP, la sortie était toujours avec un code égale à 0. Pour permettre de sortir avec une erreur, deux fonctions ont été ajoutées : win32_set_service_exit_mode et win32_set_service_exit_code.

« win32_set_service_exit_mode » permet de modifier le mode de sortie en passant l’argument à faux. PHP informera le gestionnaire des services que la sortie n’est pas correcte.

« win32_set_service_exit_code » permet de définit un code d’erreur lié a l’erreur rencontrée dans votre code. Ce numéro sera converti en « raison de l’erreur » puis enregistré dans le journal d’évènement de Windows.

Il est conseillé d’utiliser ces deux fonctions dès le lancement de votre service pour définir les paramètres de sortie. Ainsi la moindre erreur générée par PHP ou votre code déclenchera la gestion des défaillances.

Maintenant que nous pouvons signaler au gestionnaire des services que notre service défaille, il est intéressant de savoir comment sont utilisées les actions liées aux défaillances. Le gestionnaire de service tient un compteur des défaillances. Ce compteur est remis à zéro après un certain délai (1 jour pas défaut, il est configurable avec le paramètre ‘recovery_reset_period‘ lors de l’enregistrement du service) selon ce compteur, les actions sont exécutées.

Comment les actions en cas de défaillance sont-elles configurées ?
Pour cela il y a deux moyens : soit lors de l’enregistrement du service via la fonction ‘win32_create_service‘ soit en utilisant l’interface graphique du gestionnaire des services.
Avec la fonction ‘win32_create_service’, il existe plusieurs options de configuration liée à la gestion des défaillances. Le nom de toutes ces options commence par ‘recovery_’.

Dorénavant, notre service se relance s’il défaille, mais à quoi correspond le paramètre ‘recovery_delay’. Ce paramètre contient le délai entre la défaillance et l’exécution de l’action à exécuter suite à la défaillance. Il est exprimé en milliseconde et vaut 60000 millisecondes par défaut (soit 1 minute).

Comment réagit le service si la demande d’arrêt est demandée par le gestionnaire de service ?
Pour que la sortie soit correcte et que le gestionnaire de service ne considère pas que l’arrêt est une défaillance, il faut avoir informé le gestionnaire des services que votre service est stoppé via cette fonction ‘win32_set_service_status‘.

Nous avons fait le tour de cette nouvelle fonctionnalité. À vous d’expérimenter. Si vous avez des questions ou des remarques, les commentaires sont là !

Win32Service Bundle

Avec la sortie de la version 0.4 de l’extension Win32Service pour PHP, un nouveau bundle a été rendu disponible. Le but de ce bundle est de faciliter l’intégration de la librairie PHP « service-library » dans Symfony.

Ce bundle permet de limiter le travail nécessaire pour utiliser l’extension et ainsi rendre le travail plus rapide.

Voici un exemple. Vous disposez actuellement d’une commande Symfony exécutée via les tâches planifiées toutes les 2 minutes. Cette commande contient une boucle qui répète x fois le même traitement.

Voici les étapes pour transformer votre commande en service:
1 – ajouter le bundle à votre projet.
2 – ajouter la configuration pour votre service dans le fichier ‘config/package/win32_service.yaml’
3 – écrire une classe qui étant la classe abstraite « Win32Service\Model\AbstractServiceRunner »
4 – placer dans la fonction « run » le code nécessaire pour l’exécution d’un traitement.
5 – définir votre classe comme un service dans la configuration de Symfony avec le tag « win32service.runner » et un alias contenant la même valeur que la clé ‘service_id’ définit dans la configuration du bundle.

Afin de vous guider, voici un exemple concret d’un projet Symfony configuré.
1 – Le bundle a été ajouté dans le fichier ‘composer.json‘ et activé dans le fichier ‘config/bundles.php‘.
2 – Le fichier de configuration ‘config/packages/win32_service.yaml‘ a été ajouté avec un service.
3 – La classe ‘App\WindowsService\FirstService‘ étant la classe abstraite.
4 – La classe est présente dans un dossier dont toutes les classes seront considérées comme des services par Symfony. Il est uniquement nécessaire d’ajouter le tag pour ce service dans le fichier ‘config/services.yaml‘.

Il ne reste plus qu’à écrire le code et faire en sorte que la durée d’exécution de la méthode ‘run’ ne dépasse pas 30s. Cette limite est imposée par Microsoft pour toutes les actions d’un service. Le délai est également de 30 secondes pour le démarrage, la mise en pause, la reprise et l’arrêt d’un service.

Si vous avez des questions ou des suggestions, ou tout simplement un commentaire, je serai content de vous lire.

Nouveautés de Win32Service 0.4

Cette version apporte quelques nouveautés. La plus importante me semble être la gestion des défaillances du service.

Votre service fonctionne normalement et une erreur viens perturber son fonctionnement. PHP sort avec une erreur, mais vous devez relancer le service à la main.

Avec la version 0.4 de l’extension, il est possible de prédéfinir le type de sortie avec un code. Le mode de sortie par défaut est un mode gracieux qui informe juste le gestionnaire de service de l’arrêt de votre service quelques soit la cause réelle du service.

Avec ces nouvelles fonctions (win32_set_exit_mode, win32_set_exit_code), vous pouvez personnaliser le mode de sortie et le code de sortie. Ainsi si votre code lève une exception ou une erreur PHP, il est possible de la récupérer, de l’enregistrer dans un journal d’évènement puis de réaliser une sortie en erreur du service. Ainsi, le gestionnaire des services peut être configuré pour réaliser des actions lié aux défaillances.

Lors de l’arrêt du service, le gestionnaire déclenchera donc l’une des actions possibles selon le nombre de défaillances du service. Relancer le service sera surement votre premier choix. Ainsi à l’issue d’un délai d’attente, le service sera relancera correctement. Il pourra reprendre son travail sans votre intervention.

Dans cette version, quelques paramètres de configuration ont été ajoutés pour configurer le service lors de l’enregistrement auprès du gestionnaire de service.

Premier élément de configuration concerné justement la stratégie de gestion des défaillances. Quelles sont les actions à réaliser lors de la première défaillance, la seconde, les suivantes…

Ainsi, il vous est possible de définir le comportement du service lors de son enregistrement, mais également de déclarer la défaillance du service lors d’une sortie brutale pendant son exécution.

Un dernier élément de configuration apporté par cette version est la gestion des dépendances. Votre service dépend surement d’un autre service (par exemple le service de gestion du réseau). Vous pouvez maintenant déclarer ces dépendances lors de l’enregistrement du service pour que votre service soit démarré après toutes ses dépendances.

Comme à mon accoutumé, la documentation de l’extension a été mise à jour sur le site officiel de PHP tant en anglais qu’en français.

A vous de jouer avec cette nouvelle version. Je suis toujours ouvert à vos retours d’expérience, mais également a vos suggestions d’améliorations.