On n'a pas nécessairement besoin de cela.
Si les C
services doivent attendre S
d'être prêts pour pouvoir y ouvrir une connexion socket, il n'est pas nécessaire de le faire du tout. Au lieu de cela, on peut profiter de l' ouverture d' écoute précoce par les gestionnaires de services.
Plusieurs systèmes, y compris le s6 de Laurent Bercot , mon jeu d'outils NOS et systemd, ont des façons d' ouvrir une prise d'écoute dès le début, la toute première chose dans la configuration du service. Ils impliquent tous autre chose que le programme de service ouvrant les sockets d'écoute et le programme de service, lorsqu'il est appelé, recevant les sockets d'écoute en tant que descripteurs de fichiers déjà ouverts.
Avec systemd, en particulier, on crée une unité de socket qui définit la socket d'écoute. systemd ouvre l'unité de socket et la configure pour que le sous-système de mise en réseau du noyau écoute les connexions; et le transmet au service réel en tant que descripteur de fichier ouvert lorsqu'il s'agit de générer le ou les processus qui gèrent les connexions au socket. (Il peut le faire de deux manières, tout comme le inetd
pourrait, mais une discussion sur les détails des services Accept=true
versus Accept=false
dépasse le cadre de cette réponse.)
Le point important est que l'on n'a pas nécessairement besoin de plus de commande que cela. Le noyau place les connexions client dans une file d'attente jusqu'à ce que le programme de service soit initialisé et prêt à les accepter et à parler aux clients.
Quand on le fait, les protocoles de préparation sont la chose.
systemd dispose d'un ensemble de protocoles de préparation qu'il comprend, service par service spécifié avec le Type=
paramètre dans l'unité de service. Le protocole de préparation particulier qui nous intéresse ici est le notify
protocole de préparation. Avec lui, systemd est invité à attendre des messages du service, et lorsque le service est prêt, il envoie un message qui signale l'état de préparation. systemd retarde l'activation des autres services jusqu'à ce que l'état de préparation soit signalé.
Utiliser cela implique deux choses:
- Modifier le code de
S
pour qu'il appelle quelque chose comme la fonction de Pierre-Yves Ritschard notify_systemd()
ou la fonction de Cameron T Norman notify_socket()
.
- Configuration de l'unité de service pour le service avec
Type=notify
et NotifyAccess=main
.
La NotifyAccess=main
restriction (qui est la valeur par défaut) est que systemd doit savoir ignorer les messages des programmes espiègles (ou tout simplement défectueux), car tout processus sur le système peut envoyer des messages au socket de notification de systemd.
On utilise de préférence le code de Pierre-Yves Ritschard ou de Cameron T Norman car cela n'exclut pas la possibilité d'avoir ce mécanisme sur UbuntuBSD, Debian FreeBSD, FreeBSD, TrueOS, OpenBSD, etc.; ce que le code fourni par les auteurs de systemd exclut.
Un piège à éviter est le systemd-notify
programme. Il a plusieurs problèmes majeurs, dont le moindre n'est pas que les messages envoyés avec celui-ci peuvent finir par être jetés non traités par systemd. Le problème le plus important dans ce cas est qu'il ne s'exécute pas en tant que processus "principal" du service, il faut donc ouvrir les notifications de disponibilité du service S
à chaque processus du système avec NotifyAccess=all
.
Un autre piège à éviter est de penser que le forking
protocole est plus simple. Ce n'est pas. Le faire correctement implique de ne pas bifurquer et de quitter le parent jusqu'à ce que (pour une chose) tous les threads de travail du programme soient en cours d'exécution. Cela ne correspond pas à la façon dont l'écrasante majorité des démons qui bifurquent réellement.
Lectures complémentaires
systemd.service(5)
,NotifyAccess=all
accepte les messages de tous les membres du groupe de contrôle du service , ce qui ne pas impliquent que tout processus de voyous sur le système. Ceci est suffisamment sécurisé pour la plupart des cas d'utilisation. De plus, votre préoccupation concernant la portabilité vers d'autres systèmes d'exploitation n'est pas pertinente pour OP, car nous sommes déjà sur le sujet de Systemd ici.En se référant à la page de manuel pour
systemd.service(5)
, en particulier la section sur Type = , chaque type de service a une manière différente pour Systemd de déterminer qu'il est prêt à offrir des fonctionnalités à d'autres services:Si
Type=simple
, ses canaux de communication doivent être installés avant le démarrage du démon (par exemple les sockets configurés par systemd, via l'activation des sockets).Si
Type=forking
, le processus parent devrait se terminer lorsque le démarrage est terminé et que tous les canaux de communication sont configurés.Si
Type=dbus
, il est prévu que le démon acquière un nom sur le bus D-Bus, point à partir duquel systemd procédera au démarrage des unités de suivi.Si
Type=notify
, il est prévu que le démon envoie un message de notification viasd_notify(3)
ou un appel équivalent une fois le démarrage terminé. systemd poursuivra le démarrage des unités de suivi après l'envoi de ce message de notification.Pour la dernière option (envoyer un message via
sd_notify
), vous pouvez utiliser l'systemd-notify
utilitaire et n'oubliez pas de lui accorder l'accès avecNotifyAccess=all
.Étant donné que vous contrôlez le service
S
, vous êtes libre de choisir la meilleure option pour votre cas d'utilisation, ou simplement celle qui est la plus facile à mettre en œuvre.la source
comme ça:
S.service
C0.service
C1.service
C9.service
Où / usr / bin / myBinary effectue un appel sd_notify READY = 1 lorsque son initialisation est terminée.
Selon la façon dont vous souhaitez que la dépendance se comporte, vous pouvez utiliser PartOf, Requirements ou BindsTo ou autres .
la source