Método à prova de balas para lidar com execuções duplicadas

2

Eu tenho um script no meu roteador executando a cada 30 minutos pelo cron. O roteador ocasionalmente o executa duas vezes, com poucos segundos de diferença, mas somente quando o roteador está inicializando. Há algumas semanas, para evitar que fosse executado duas vezes simultaneamente, usei o pidof para verificar, evitando intencionalmente qualquer método de contagem de linhas - para evitar possíveis problemas.

for pid in $(pidof DoubleDDNS); do
  if [ $pid != $$ ]; then
    echo "DoubleDDNS [no2run] Exiting"
    exit 1
  fi
done

Mas. Eu só tive um problema. Por algum motivo, o roteador ficou bizzrk. Meu roteiro não terminou, com muita atenção. Ficou preso na memória para sempre. Assim, a verificação acima impediu que meu script fosse executado novamente enquanto a execução original (mais antiga) não terminava seu trabalho. Isso criou um problema (não relatar um novo endereço IP da WAN para DDNS).

Eu não acho que seja culpa do meu roteiro, já que não há comandos nele que possam deixá-lo preso. O script é executado por mais de 8 meses em vários roteadores sem nenhum problema. Está bem escrito, manuseando e testando todos os possíveis erros. O roteador funcionou principalmente, mas muitas coisas foram quebradas (por exemplo, ssl). O roteador não relatou nenhuma de suas 3 memórias como preenchidas (o que pode ou não ser verdade). Ele não iria sequer resetar quando eu selecionei reset em sua própria WebGUI e tive que ser resetado com o botão liga / desliga!

Então, como eu faço o teste de minha segunda execução? Estou pensando: inclua uma verificação se a instância anterior estava em execução por mais de 60 segundos e, em caso afirmativo, seria

  1. tente matar qualquer instância antiga
  2. continue apesar de ser executado em duplicado. O script é executado nos 3º e 33º minutos de cada hora e a execução única dura < 15 segundos.

Perguntas (de preferência sem qualquer geração de arquivos, mas talvez minha evitação de filelock tenha sido uma solução ruim, então aconselhe):

  1. Como detectar quantos anos tem a execução anterior?
  2. Alguma ideia melhor que a minha?
  3. existe uma maneira de suicidar um script: se o script não tiver sido concluído em 60 segundos, elimine essa instância de script

Tenha em mente: roteador, sh e busybox. Então, um conjunto limitado de coisas está disponível. Os roteadores da Asus Roteador Asus RT-AC * U são usados com o Merlin fw.

    
por Pila 20.10.2016 / 17:27

1 resposta

0

Aqui está uma maquete da minha versão à prova de balas. É manipulado para mostrar lógica. Ele roda no meu roteador OK.

#!/bin/sh

age_max_sec=50

LOCKFILE=lock.txt
if [ -e ${LOCKFILE} ]; then
    echo "lockfile exists"
    if kill -0 'cat ${LOCKFILE}'; then
        echo "script runs in mem" 
        lock_date='date -r ${LOCKFILE} +%s'
        now='date +%s'
        lock_age=$(($now-$lock_date))
        if [ $lock_ag e -gt $age_max_sec ]; then
            echo "DoubleDDNS (no2runKILL)"
            kill 'cat ${LOCKFILE}'
        else
            echo "DoubleDDNS (no2runOK), age $lock_age seconds, quit this run"
            exit 1
        fi   
    else
        echo "not allready running, go ahead"
    fi
fi

echo "working on"

# overkill???? just in case, scorched earth check.
filename=${0##*/}
for pid in $(pidof $filename); do
    if [ $pid != $$ ]; then
        echo "DoubleDDNS (no3runKILL)"
        kill -9 $pid
    fi
done

# make sure the lockfile is removed when we exit and then claim it
trap "rm -f ${LOCKFILE}; exit" INT TERM EXIT
echo $$ > ${LOCKFILE}

# main program here

rm -f ${LOCKFILE}

echo "done"

Acho que devo usar o arquivo de bloqueio se quiser verificar a idade da execução anterior. Então, faça um lockfile com pid. Se lockfile não for mais antigo que o limite de segundos, saia. Se for mais antigo, mate a instância anterior. No meu roteador, não tenho melhores formas disponíveis para verificações que fiz.

Eu preciso de verificação de terra queimada ou é um exagero? Depois que as verificações legítimas do lockfile são feitas, estou verificando novamente se há um processo remanescente mas quebrado ainda na memória e mato se encontrado. O problema é: eu não tenho como testá-lo até que um desastre real ocorra novamente e a limpeza regular não consiga limpá-lo. Se não for um exagero ...

Deve-se notar que a disponibilidade do serviço NTP pode influenciar bloqueios cronometrados e pílula de suicídio. Por exemplo. minha primeira execução do script acima ocorreria cerca de 4 segundos antes que o NTP consertasse o tempo. Então, devemos levar essas coisas em consideração.

A pílula de suicídio fornecida acima pelo DopeGhoti funciona perfeitamente. Então, agora é apenas uma questão de julgar qual combo usar. Ou todos eles? Lockfile, lançamento programado, terra queimada e suicídio. Hmm, parece um exagero, mas não vejo nenhum deles trabalhando contra outros, mas em perfeita harmonia (paranóica). Comentários são bem vindos.

    
por 21.10.2016 / 13:01