2016-08-16 6 views
1

J'écris un système de serveur qui fonctionne en arrière-plan. En termes très simplifiés, il a son propre langage de script, ce qui signifie qu'un processus peut être écrit dans ce langage pour fonctionner seul, ou il peut appeler un autre processus, etc. Je convertis ce système à partir d'un cron-job PHP trivial dans dont une seule instance est autorisée à la fois pour un ensemble de processus de longue durée gérés par Supervisor. Dans cet esprit, je suis conscient que ces processus peuvent être tués à tout moment, soit par moi-même en cours de développement, ou peut-être par Supervisord dans le cours normal de l'arrêt ou du redémarrage d'un travailleur. Je voudrais ajouter un traitement de signal approprié pour s'assurer que les travailleurs ranger après eux-mêmes, et se connecter où une tâche a été laissée dans un état interrompu le cas échéant.Comment effectuer des tests d'intégration fiables de la gestion des signaux Unix en PHP?

J'ai travaillé sur la façon d'activer la gestion du signal en utilisant des ticks et pcntl_signal(), et ma gestion semble actuellement fonctionner correctement. Cependant, je voudrais tester cela pour s'assurer qu'il est fiable. J'ai écrit quelques tests d'intégration précoce, mais ils ne se sentent pas très solides, principalement parce que pendant le développement il y avait toutes sortes de problèmes de conditions de course bizarres qui étaient difficiles à cerner. Je voudrais des conseils ou des instructions sur la façon d'envoyer des signaux kill dans des tests PHPUnit, dans le but d'améliorer la confiance que ma gestion sig est robuste. Ma stratégie actuelle:

  • Utilise PHPUnit
  • Comme le système de base fonctionne, il crée des fichiers journaux de différents types, qui peut être utilisé pour surveiller quand tuer la tâche
  • Le système de base est lancé à l'aide d'un séparer le script PHP en arrière-plan en utilisant une commande system() dans le test PHPUnit. Ma commande est similaire à php script.php > $logFile 2>&1 &, c'est à dire rediriger toutes les sorties vers un fichier journal, puis la pousser en arrière-plan pour que la méthode de test puisse la surveiller
  • Le script d'arrière-plan écrit son PID dans un fichier, qui sera le PID à tuer
  • C'est repris de manière fiable par le test par balayage à plusieurs reprises et usleep ing entre les scans
  • le test attend ensuite un état spécifique en balayant la base de données, usleep ing entre les scans, et l'émission d'un kill <pid> lorsqu'il est prêt
  • Il attend ensuite que le gestionnaire de signal se mette en marche et écrive un nouvel état de base de données, usleep pour éviter le jambon Mering the base de données
  • Enfin, il sera soit déterminer si la base de données est dans un état correct ou non, après un délai maximum, qui passe/échoue un test.

Bien sûr, avec toutes ces attentes/vérifications, il se sent un peu rauque, et tout à fait mûr pour des conditions de course de toutes sortes. Mon sentiment actuel est que les tests échoueront dans environ 2% des cas, mais je n'ai pas réussi à faire échouer le test pendant un jour ou deux. J'ai l'intention de faire quelques tests d'immersion, et si j'en ai des échecs, je les publierai ici. Je me demande si je peux le simplifier en demandant au système à tester kill lui-même, ce qui supprimera deux niveaux de vérification d'attente (l'un pour attendre le PID, et l'autre pour attendre que la base de données entre dans l'état correct avant la commande kill) . Cela laisserait toujours la boucle de vérification d'attente après l'émission de la mise à mort, mais je pourrais encore trouver que cette vérification n'est pas un problème en pratique.Cela dit, je suis conscient que toute mon approche peut être entravée, et il y a une meilleure approche pour faire ce genre de chose. Des idées? À l'heure actuelle, ma pensée est juste d'augmenter mes délais d'attente, au cas où PHPUnit introduit des retards étranges. Je verrai aussi si je peux obtenir un cas d'échec pour examiner les journaux.


† Ah, malheureusement, cela ne simplifiera pas beaucoup les choses. Je l'ai juste essayé sur un simple test d'intégration de signal que je considère comme fiable, et puisque le system() en arrière-plan revient immédiatement, il doit encore attendre en boucle pour identifier le bon enregistrement de journal, et ensuite pour le bon résultat après la mort. Cependant, il n'est plus nécessaire d'attendre l'écriture d'un PID dans un fichier temporaire, ce qui élimine au moins une boucle.

+0

probablement moyen d'élargir. –

+0

Je peux voir comment quelqu'un pourrait le considérer comme une affaire de bord. Néanmoins, je me demande si cela peut sembler trop large parce que, paradoxalement, j'ai précisé trop de détails? En un mot, c'est demander un moyen de rendre plus fiables les tests impliquant les signaux Posix - j'espère que quelqu'un ici pourrait avoir de l'expérience avec ça! Nous verrons... – halfer

Répondre

-1

Comme je l'ai mentionné dans la question, le premier changement de fiabilité que j'ai essayé était d'injecter la capacité pour les tâches de l'opérateur pour exécuter kill sur eux-mêmes. Dans mon cas, cela a été intégré dans le système, mais les lecteurs peuvent trouver que l'écriture d'une classe de test enfant et la modification de leur configuration DI serait un moyen pratique de le faire.

Cela semble avoir beaucoup amélioré la fiabilité. A l'origine, il y avait plusieurs boucles d'attente dans les essais, et le test devraient exécuter le kill au bon moment:

  1. Attendez que le PID de l'enfant à devenir disponible
  2. Attendez que les fichiers journaux des enfants pour indiquer qu'il est prêt à tuer
  3. le problème kill
  4. Attendez que les fichiers journaux des enfants pour indiquer le gestionnaire de signal s'exécute correctement

la question est peut-être en (2) - Si cela est trop court, le kill peut parfois arriver trop tard, et même si un temps d'attente maximum est trouvé, si le CPU est sous une charge inattendue, il peut encore être sujet à une panne.

J'ai maintenant écrit un script rapide pour exécuter plusieurs fois les tests PHPUnit, soit pour 200 itérations, soit pour le premier échec, selon la première éventualité. Cela passe maintenant 200 itérations, donc pour le moment je considérerai que la fiabilité du test a augmenté. Cependant, je vais mettre à jour ici si cela change - peut-être exécuter les tests avec un haut nice va provoquer un échec.

D'autres réponses sont toujours les bienvenues.