- Lorsqu’un script Bash effectue des tentatives de connexion répétées pour vérifier l’état d’un serveur web, le serveur peut de façon inattendue entrer dans une boucle infinie
timeout, l’outil qui permet de résoudre ce problème, définit une durée limite d’exécution pour une commande et, en cas de dépassement, envoie un signal pour tenter de terminer le processus
- Il ne peut pas être appliqué directement à des shell built-ins comme
until, mais on peut contourner cela en encapsulant dans un processus bash ou en séparant la logique dans un script
Attente d’un serveur web et problème de boucle infinie dans un script Bash
- En pratique, des scripts Bash sont utilisés pour configurer un serveur web et vérifier son état
- La structure consiste à suspendre l’étape suivante tant que le serveur n’est pas démarré, ce qui fonctionne normalement sans problème
- Mais si le serveur plante pendant son démarrage, le script peut entrer dans une boucle infinie, d’où la nécessité de corriger ce comportement
Exemple d’utilisation de until et ses limites
Introduction de l’utilitaire timeout
- La commande
timeout termine une commande en lui envoyant un signal (SIGTERM, etc.) si elle ne se termine pas dans le délai imparti
- Exemple : avec
timeout 1s sleep 5, une tentative de terminer le processus sleep est effectuée au bout d’une seconde
- À la fin, elle renvoie un code de sortie anormal (par ex. 124)
Tentative de combinaison de timeout et until, et problème rencontré
Solution : encapsuler dans un processus Bash ou utiliser un script externe
1 commentaires
Avis Hacker News
Mon astuce méconnue préférée est l’injection de pannes avec
strace, qui permet de tester différents échecs d’appels systèmePlus de détails dans ce lien connexe
Je trouve cette fonctionnalité vraiment incroyable, et j’aurais aimé la connaître plus tôt
Comme je n’avais aucun moyen de tester les branches d’échec, je remplaçais temporairement des parties de fonctions par du code provisoire, mais cette astuce semble permettre une approche plus concise
Cette méthode a l’air vraiment utile
Je me demande s’il existe quelque chose de similaire sous Windows
Pour les vérifications d’état d’un service, il est suggéré que la meilleure approche consiste à définir à la fois une durée maximale de timeout et un nombre maximal de tentatives
En général, on réessaie jusqu’à X fois, puis on considère l’opération en échec après au plus Y unités de temps
Il est souligné qu’il faut décider de l’échec aussi vite que possible plutôt que d’attendre trop longtemps
Dans les services standard, les dépendances de conteneurs sont suffisamment garanties et les health checks ne démarrent qu’une fois que tout est prêt à fonctionner
Voir
Init Containerdans Kubernetes,dependsOndans AWS ECS, etdepends_ondans Docker ComposeUn exemple de script shell POSIX est fourni
Mais il est aussi mentionné que
curlintègre déjà cette fonctionnalité, ce qui permet de l’utiliser directement ainsi sans script séparéSur Mac, la commande
timeoutn’est pas fournie par défaut, donc quelqu’un a raconté avoir fait plusieurs essais pour implémenter un timeout uniquement avec des builtins bashIl est expliqué que la commande
sleepest standard en POSIX et peut donc être utiliséeUn exemple d’implémentation de timeout comme ci-dessous est donné
Une fonction
times_upgère le timeoutUn exemple de test répète une boucle
for20 fois avec un timeout de 10 secondesQuelqu’un a partagé avoir implémenté une méthode similaire il y a 12 ans en suivant un conseil sur Stack Overflow
Plus de détails dans ce lien de référence
Il a insisté sur le fait que le code n’utilisait que des builtins shell et
sleep, et qu’il devait impérativement rester compatible POSIXIl signale qu’il faut faire attention, car la syntaxe bash
{1..20}de l’exemple n’est pas POSIXSon amélioration consistait à faire renvoyer
truesi le timeout ne se produit pas, etfalses’il se produit, afin de simplifier la gestion d’erreurs dans le scriptUne méthode très simple est partagée ci-dessous : exécuter la commande et
sleepen parallèle, puis arrêter la commande avec un signal une fois le délai écouléUn exemple de script d’il y a 13 ans utilisant
read -tpour implémenter un timeout est également partagéLien
Il est indiqué que
curldispose déjà du drapeau--retry-connrefused, ce qui permet d’utiliser directement cette fonctionnalité sans boucle shellLorsqu’on utilise
bash -cet qu’il faut passer des variables, il est recommandé d’ajouter les arguments de la manière suivanteUne explication est donnée sur la raison d’utiliser
"--"et sur le rôle deargv[0]Il est aussi mentionné qu’on peut utiliser
printf %q, mais qu’une approche compatible Bourne est préféréeIl est expliqué que
"--"est très clairement compris comme un marqueur de fin d’options par bash et par la plupart des CLI Unix/LinuxRéférence associée
Busybox détermine le programme à exécuter à partir de la valeur de
argv[0], ce qui permet de le définir commels,mv,cp, etc.Lorsqu’une logique de répétition est nécessaire, voici la méthode généralement utilisée
Ce n’est pas très élégant, mais c’est généralement correct, et à un niveau plus avancé on peut appliquer un backoff exponentiel
Il est aussi mentionné que cela présente des avantages en matière d’extensibilité
ShellCheck recommande dans ce cas d’utiliser la variable
_pour gérer le problèmeLien de référence
Il est souligné que la fonction
eventually_succeedspeut, selon le contexte, avoir besoin d’un timeout ou d’un code défensif supplémentaireRappel qu’il faut toujours écrire du code défensif en POSIX / processus / E/S
Quelqu’un a raconté qu’autrefois, lorsque ses enfants étaient petits, il utilisait la commande ci-dessous comme une sorte d’outil de contrôle parental pour limiter le visionnage à un seul programme de 30 minutes
L’idée est jugée très utile
Comme il faut envoyer des signaux à un sous-processus, quelqu’un dit ne pas trop aimer utiliser une commande inline ou un fichier de script temporaire
Sa méthode préférée consiste à mettre la logique souhaitée dans une fonction, à l’exporter, puis à l’envelopper avec
timeout bash -cCela rejoint la méthode sûre de passage d’arguments mentionnée par aidenn0
"$@"à la finSinon, les arguments contenant des espaces ne sont pas transmis correctement
Un exemple avec
long_fnest partagé pour le vérifierQuelqu’un rappelle un ancien billet de blog où
timeoutétait mentionnéLe blog associé est recommandé à ceux qui s’intéressent davantage aux langages de programmation généraux qu’au shell, ou au fonctionnement interne
Dans un environnement Kubernetes, quelqu’un partage avoir ajouté des timeouts à des commandes
Des scripts shell POSIX comme
await-cmd.sh,await-http.shetawait-tcp.shsont présentés comme mûrs et assez utiles dans certaines situationsLien vers le projet associé