Olho de Cylon do systemd

Um recurso imbatível do systemd é o olho de Cylon! 🤩

Quando uma unidade está demorando demais para iniciar ou terminar, o systemd exibe, desde a versão 198, esta temível animação:

http://youtu.be/PQfOwtBe9Bs

O limite de tempo para desistir de esperar é de 90s se não for especificado no arquivo de unidade, seguindo a configuração global de /etc/systemd/system.conf. Os parâmetros para modificar são DefaultTimeoutStartSec= e DefaultTimeoutStopSec=. Evite mexer na configuração global. Configure em cada unidade quando necessário com TimeoutStartSec=, TimeoutStopSec= e TimeoutSec= (o último configura os anteriores de uma só vez).

Se não tiver aí nenhum programa mal comportado (ainda bem!), aqui está o código do daemon fajuto que usei:

fajuto.c

#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <systemd/sd-daemon.h>
#include <systemd/sd-journal.h>

const int wait_time = 40;

void signal_handler(int signum)
{
    switch(signum)
    {
        case SIGABRT:
            sd_journal_print(LOG_NOTICE, "SIGABRT recebido, saindo com erro.");
            exit(EXIT_FAILURE);
            break;
        case SIGTERM:
            sd_journal_print(LOG_NOTICE, "SIGTERM recebido, esperando %ds para sair...", wait_time);
            sleep(wait_time);
            exit(EXIT_SUCCESS);
            break;
    }
}

int main(void)
{
    signal(SIGABRT, signal_handler);
    signal(SIGTERM, signal_handler);

    sd_notify(0, "READY=1");

    sd_journal_print(LOG_NOTICE, "Fajuto rodando. Passar bem.");

    while(1)
      ;

    return EXIT_SUCCESS;
}

/etc/systemd/system/fajuto.service

[Unit]
Description=Fajuto

[Service]
Type=notify
ExecStart=/usr/local/bin/fajuto

[Install]
WantedBy=multi-user.target

Compilação/instalação:

# yum -y install gcc glibc-devel systemd-devel
$ gcc -o fajuto fajuto.c -lsystemd
$ strip fajuto
# install fajuto /usr/local/bin

# systemctl daemon-reload
# systemctl enable fajuto.service
# systemctl start fajuto.service

O código nada faz. É apenas um loop infinito. Ao receber SIGABRT, termina com exit code 1 (falha). Quando recebe SIGTERM, espera 40 segundos antes de terminar com exit code 0 (sucesso). Ao finalizar os processos durante o desligamento do sistema, a demora faz o systemd acionar o olho de Cylon (o temporizador é de 5 segundos). Podemos observar o comportamento, sem a animação 😥, com:

# systemctl --no-block stop fajuto.service
# systemctl status fajuto.service
fajuto.service - Fajuto
   Loaded: loaded (/etc/systemd/system/fajuto.service; enabled)
   Active: deactivating (stop-sigterm) since Sáb 2014-01-25 19:39:48 BRST; 14s ago
 Main PID: 219 (fajuto)
   CGroup: /system.slice/fajuto.service
           └─219 /usr/local/bin/fajuto

Jan 25 19:37:48 PLUTO systemd[1]: Starting Fajuto...
Jan 25 19:37:48 PLUTO fajuto[219]: Fajuto rodando. Passar bem.
Jan 25 19:37:48 PLUTO systemd[1]: Started Fajuto.
Jan 25 19:39:48 PLUTO systemd[1]: Stopping Fajuto...
Jan 25 19:39:48 PLUTO fajuto[219]: SIGTERM recebido, esperando 40s para sair...

Veja que, na saída de systemctl status, o estado do serviço ficará em deactivating (stop-sigterm) durante os 40 segundos até o programa finalizar.

Testemos também systemctl kill:

# systemctl start fajuto.service
# systemctl kill --signal=SIGABRT fajuto.service
# systemctl status fajuto.service
fajuto.service - Fajuto
   Loaded: loaded (/etc/systemd/system/fajuto.service; enabled)
   Active: failed (Result: exit-code) since Sáb 2014-01-25 19:42:43 BRST; 8s ago
  Process: 701 ExecStart=/usr/local/bin/fajuto (code=exited, status=1/FAILURE)
 Main PID: 701 (code=exited, status=1/FAILURE)

Jan 25 19:41:52 PLUTO fajuto[701]: Fajuto rodando. Passar bem.
Jan 25 19:41:52 PLUTO systemd[1]: Started Fajuto.
Jan 25 19:42:43 PLUTO fajuto[701]: SIGABRT recebido, saindo com erro.
Jan 25 19:42:43 PLUTO systemd[1]: fajuto.service: main process exited, code=exited, status=1/FAILURE
Jan 25 19:42:43 PLUTO systemd[1]: Unit fajuto.service entered failed state.

SuccessExitStatus=1 na seção [Service], por exemplo, faria o systemd considerar exit code 1 como sucesso e o serviço não entraria em estado de falha.

Para desinstalar:

# systemctl disable --now fajuto.service
# rm -f /usr/local/bin/fajuto
# rm -f /etc/systemd/system/fajuto.service
# systemctl daemon-reload

Referências:
Battlestar Galactica Original Cylon Centurions

Relacionado:
Modificar parâmetros dos arquivos de unidade do systemd
Básico dos arquivos de unidade do systemd
Ordenação no systemd
systemctl cat/edit
systemctl enable|disable|mask --now
systemctl revert

Comentários