Per gestire l’emergenza Covid-19 è necessario elaborare e trasmettere diversi flussi informativi a diverse piattaforme (piattaforme aziendali, bucket regionali, in formato csv o excel, applicativi di gestione casi, dashboard di aggregazione o analisi dei dati, etc.).

Ho quindi predisposto diversi task che:

  • richiamano dei piccoli applicativi Perl per estrarre via SQL le informazioni necessarie, le trasformano, e le salvano in file in formato CSV
  • comprimono i dati, eventualmente con password complesse
  • trasmettono i dati verso bucket aws, su altri server Qlik o Pentaho
  • generano mail puntuali o di riepilogo

Il testo che segue non è un “manuale” su come fare le cose, ma un elenco di appunti che mi aiutano a ricordare quali operazioni ho fatto e qual è la logica sottostante.

La schedulazione avviene con il servizio crond. Tuttavia nel corso del tempo il numero di task è diventato numeroso, la configurazione della crontab è diventa complessa, e modificare o monitorare il corretto funzionamento dei task è diventato poco agevole.

Ho quindi voluto riorganizzare il servizio con il seguente sistema. La tabella con i task è minimale, questo un task che necessita di essere eseguito ogni ora:

0  *  *  *  * /home/fede/scripts/hourly_tasks.sh

Questo task a sua volta si occupa di lanciare tutti gli script che devono essere eseguiti ogni ora, gestendone correttamente l’output stdout e stderr nei file di log opportuni:

#!/bin/bash

LOG_FILE=/var/log/covid_out.log
LOG_ERROR=/var/log/covid_err.log

exec 1>>"$LOG_FILE" 2>>"$LOG_ERROR"

./task01.sh &
./task02.sh &
./task03.sh &
...

In questo caso i vari task vengono eseguiti in parallelo, ed ereditano gli output verso i file di log.

Tuttavia per ogni task voglio fare in modo che il log contenga la data e l’ora, ed il nome del task eseguito:

#!/bin/bash
PROGNAME=$(basename $0)

exec  > >(sed --unbuffered "s/^/$(date +'%Y-%m-%d %H:%M:%S'),$PROGNAME: /")
exec 2> >(sed --unbuffered "s/^/$(date +'%Y-%m-%d %H:%M:%S'),$PROGNAME: /" >&2)

...

Il parametro --unbuffered assicura che la singola riga viene processata immediatamente, senza utilizzare un buffer, in modo che data e l’ora presentate nel file di output siano quelle effettive di quando l’output è stato realizzato e che i vari output siano sequenziali.

Inoltre per gestire correttamente eventuali errori, ho predisposto una funzione come segue:

error_exit()
{
        echo "${1:-"Unknown Error"}" 1>&2
        exit 1
}

La struttura completa del task risulta essere questa:

#!/bin/bash
PROGNAME=$(basename $0)

error_exit()
{
        echo "${1:-"Unknown Error"}" 1>&2
        exit 1
}

exec  > >(sed --unbuffered "s/^/$(date +'%Y-%m-%d %H:%M:%S'),$PROGNAME: /")
exec 2> >(sed --unbuffered "s/^/$(date +'%Y-%m-%d %H:%M:%S'),$PROGNAME: /" >&2)

echo "Inizio elaborazione"

perl "extract.pl" -prepare || error_exit "$LINENO: Errore preparazione dati."
perl "extract.pl" -extract > $output || error_exit "$LINENO: Errore estrazione dati."

...

Come scaricare un file più recente da aws via cli:

latest=`$AWS s3 ls s3://bucket/path/documento | sort | tail -1 | awk '{ print $4 }'`                   
$AWS s3 cp --no-progress s3://bucket/path/$latest /home/fede/csv/documento.csv

Per scaricare il file più recente da un altro unix, in questo caso utilizzando sshpass (da valutare ovviamente se è la soluzione opportuna):

latest=$(sshpass -p $pass ssh fede@server 'ls -t /var/export/documento* | head -1')
sshpass -p $pass scp fede@server:/$latest $output_dir/$output_file