Não é necessário necessariamente isso.
Se os C
serviços precisarem esperar para S
estarem prontos para poderem abrir uma conexão de soquete, não será necessário fazer isso. Em vez disso, pode-se tirar proveito da abertura do soquete de escuta precoce pelos gerentes de serviço.
Vários sistemas, incluindo o s6 de Laurent Bercot , o meu nosh toolset e o systemd, têm maneiras pelas quais um soquete de escuta pode ser aberto desde o início, a primeira coisa na configuração do serviço. Todos eles envolvem algo diferente do programa de serviço que abre o (s) soquete (s) de escuta e o programa de serviço, quando chamado, recebe os soquetes de escuta como descritores de arquivo já abertos.
Com o systemd, especificamente, cria-se uma unidade de soquete que define o soquete de escuta. systemd abre a unidade de soquete e a configura para que o subsistema de rede do kernel esteja escutando as conexões; e o passa para o serviço real como um descritor de arquivo aberto quando se trata de gerar o (s) processo (s) que tratam das conexões com o soquete. (Ele pode fazer isso de duas maneiras, da mesma forma que inetd
poderia, mas uma discussão dos detalhes dos serviços Accept=true
versus Accept=false
está além do escopo desta resposta.)
O ponto importante é que não é necessário mais pedidos do que isso. O kernel agrupa as conexões do cliente em uma fila até que o programa de serviço seja inicializado e pronto para aceitá-las e conversar com os clientes.
Quando se faz, protocolos de prontidão são a coisa certa.
O systemd possui um conjunto de protocolos de prontidão que ele entende, serviço especificado por serviço com a Type=
configuração na unidade de serviço. O protocolo de prontidão particular de interesse aqui é o notify
protocolo de prontidão. Com isso, o systemd é instruído a esperar mensagens do serviço e, quando o serviço estiver pronto, envia uma mensagem que sinaliza prontidão. systemd atrasa a ativação de outros serviços até que a prontidão seja sinalizada.
Fazer uso disso envolve duas coisas:
- Modificando o código de
S
modo que chame algo como a função de Pierre-Yves Ritschard notify_systemd()
ou a função de Cameron T. Norman notify_socket()
.
- Configurando a unidade de serviço para o serviço com
Type=notify
e NotifyAccess=main
.
A NotifyAccess=main
restrição (que é o padrão) é porque o systemd precisa saber para ignorar mensagens de programas maliciosos (ou simplesmente defeituosos), porque qualquer processo no sistema pode enviar mensagens para o soquete de notificação do systemd.
Utiliza-se o código de Pierre-Yves Ritschard ou Cameron T Norman como preferência, porque não exclui a possibilidade de ter esse mecanismo no UbuntuBSD, Debian FreeBSD, real FreeBSD, TrueBS, TrueOS, OpenBSD e assim por diante; que o código fornecido pelos autores do sistema exclui.
Uma armadilha a evitar é o systemd-notify
programa. Ele tem vários problemas importantes, e o menos importante é que as mensagens enviadas com ele podem acabar sendo descartadas sem serem processadas pelo systemd. O problema mais importante nesse caso é que ele não é executado como o processo "principal" do serviço; portanto, é necessário abrir as notificações de prontidão do serviço S
para todos os processos do sistema NotifyAccess=all
.
Outra armadilha a evitar é pensar que o forking
protocolo é mais simples. Não é. Fazê-lo corretamente envolve não bifurcar e sair do pai até que (por um lado) todos os threads de trabalho do programa estejam em execução. Isso não corresponde à forma como a esmagadora maioria dos daemons que bifurcam realmente se bifurcam.
Leitura adicional
systemd.service(5)
,NotifyAccess=all
aceitará mensagens de todos os membros do grupo de controle do serviço , o que não implica em nenhum processo invasor no sistema. Isso é seguro o suficiente para a maioria dos casos de uso. Além disso, sua preocupação com a portabilidade para outros sistemas operacionais não é relevante para o OP, pois já estamos no tópico Systemd aqui.Referindo-se à página de manual para
systemd.service(5)
, especificamente a seção sobre Type = , cada tipo de serviço possui uma maneira diferente para o Systemd determinar que está pronto para oferecer funcionalidade a outros serviços:Se
Type=simple
, seus canais de comunicação devem ser instalados antes da inicialização do daemon (por exemplo, soquetes configurados pelo systemd, via ativação do soquete).Se
Type=forking
, espera-se que o processo pai saia quando a inicialização estiver concluída e todos os canais de comunicação estiverem configurados.Se
Type=dbus
, espera-se que o daemon adquira um nome no barramento D-Bus, quando o systemd prosseguirá com o início das unidades de acompanhamento.Se
Type=notify
, espera-se que o daemon envie uma mensagem de notificação por meio desd_notify(3)
ou uma chamada equivalente quando concluir a inicialização. O systemd continuará com as unidades de acompanhamento após o envio desta mensagem de notificação.Para a última opção (enviando uma mensagem por
sd_notify
), você pode usar osystemd-notify
utilitário e lembre-se de conceder acesso a eleNotifyAccess=all
.Como você tem controle sobre o serviço
S
, pode escolher a melhor opção para o seu caso de uso ou simplesmente a mais fácil de implementar.fonte
como isso:
S.service
C0.service
C1.service
C9.service
Onde / usr / bin / myBinary faz uma chamada sd_notify READY = 1 quando a inicialização estiver concluída.
Dependendo de como você deseja que a dependência se comporte, você pode usar PartOf, Requer ou BindsTo ou outros .
fonte