query r.e executando scripts de loop em paralelo

3

Eu tenho o seguinte em um script de shell:

for file in $local_dir/myfile.log.*; 
    do 
        file_name=$(basename $file); 
        server_name=$(echo $file_name | cut -f 3 -d '.');
        file_location=$(echo $file);

        mv $file_location $local_dir/in_progress1.log

        mysql -hxxx -P3306 -uxxx -pxxx -e "set @server_name='${server_name}'; source ${sql_script};"

        rm $local_dir/in_progress1.log
    done

Basicamente, ele obtém todos os arquivos em um diretório que corresponde aos critérios, extrai um nome de servidor do nome do arquivo antes de passá-lo para um script MySQL para processamento.

O que eu estou querendo saber é se eu tenho 10 arquivos que levam 60 segundos para completar, e depois de 5 minutos eu inicio uma segunda instância do shell script:

  • a) o segundo script ainda verá os arquivos que não foram processados
  • b) causará problemas na primeira instância se excluir arquivos

ou poderei executá-las em paralelo sem problemas?

    
por IGGt 05.11.2015 / 16:04

3 respostas

2

Supõe-se que "60 segundos" (e até "5 minutos") é apenas uma boa estimativa e que existe o risco de que o primeiro lote ainda esteja em andamento quando o segundo lote for iniciado. Se você deseja separar os lotes (e se não houver nenhum problema além dos arquivos de log em uma sobreposição ocasional), uma abordagem melhor seria fazer um número de lote como parte da convenção de nomenclatura de arquivos em andamento.

Algo parecido com isto:

[[ -s ]] $local_dir/batch || echo 0 > $local_dir/batch
batch=$(echo $local_dir/batch)
expr $batch + 1 >$local_dir/batch

antes do loop for e, em seguida, no início do loop, verifique se o padrão corresponde a um arquivo real

[[ -f "$file" ]] || continue

e use o número do lote no nome do arquivo:

mv $file_location $local_dir/in_progress$batch.log

e para frente. Isso reduz o risco de colisão.

    
por 05.11.2015 / 16:24
1

Existe uma resposta acima que fornece algumas boas soluções para o problema, mas pensei em fornecer uma explicação sobre o porquê de qual é o problema.

Na maioria das vezes: desde que seus arquivos de log renomeados (os em andamento) não atendam aos critérios, você é provavelmente seguro para executar isso com mínimo risco. Você ainda receberá alguns erros ...

Sua lista de arquivos é gerada na execução do script. Então, o que acabaria acontecendo é isso:

Script A obtém uma lista de 10 files . Começa o processamento, 5 files em (5 restantes) script B obtém uma lista de 5 remaining files , inicia o processamento. Script a , em seguida, processa o próximo arquivo em sua lista (que é o mesmo que o arquivo script B começou a processar). Ocorreu um erro porque o arquivo foi renomeado. Assim, com o tratamento de erros, isso poderia, teoricamente, passar para a próxima lista e funcionar sem problemas. Mas, obviamente, há sempre a chance de as estrelas se alinharem, mas os scripts atingem o mesmo arquivo ao mesmo tempo, e algo inesperado acontece. Pese esse risco como você vai.

Uma solução potencialmente mais elegante seria converter isso em um script python e examinar parallel for loops , o que permitiria criar um único loop e executá-lo em paralelo, permitindo que um script faça o trabalho de dois ou mais.

    
por 05.11.2015 / 16:38
1

Outra maneira de fazer isso é implementar uma fila em lote simples no seu script.

No início do script, você poderia fazer algo assim:

mkdir -p $localdir/batch
BATCHTMP=$(mktemp batch.XXXXXXXXXX)
MYBATCH="$localdir/batch/batch.$$"

# get list of current log files
find $local_dir/ -name 'myfile.log.*' > "$BATCHTMP"

# exclude any log files already in other batches
grep -vF -f <(sort -u $localdir/batch/batch.*) < "$BATCHTMP" > "$MYBATCH"

rm -f "$BATCHTMP"

# only process log files that are in my batch
for lf in $(cat "$MYBATCH") ; do
....
# somewhere in here, mv or rm the logfile being processed
# so it doesn't get processed again in a later batch run
done

rm -f "$MYBATCH"

Este é, claro, apenas um esboço simples do que precisa ser feito.

BTW, isso também pode ser feito em um script de wrapper que não faz nada além de gerar o arquivo em lote e, em seguida, executar o script principal.

    
por 05.11.2015 / 23:03