diff --git a/scripts/cron_book.sh b/scripts/cron_book.sh index 479dada..0335bda 100755 --- a/scripts/cron_book.sh +++ b/scripts/cron_book.sh @@ -35,10 +35,16 @@ mkdir -p logs # partire anche quando book_execute fallisce per la stessa ragione. Non blocca (exit 2 # = allarme inviato); l'azione a un allarme e' manuale, vedi src/live/venue_watch.py. uv run python scripts/live/venue_watch.py --quiet || true - uv run python scripts/live/book_execute.py --execute + # LOCK SUL CONTO (#36): cuscino_watch (cron_cuscino.sh, :53) puo' mandare ordini spot USDE + # sullo stesso conto — separati solo dal tempo, giri fino a 659s misurati. `flock -n` (mai + # `-w`, un SIGTERM a meta' ordine perde la riga di log): se cuscino_watch tiene il lock questo + # giro si SALTA (rc 75) invece di sovrapporsi. Niente kill/timeout sul comando. + flock -n -E 75 logs/.conto.lock uv run python scripts/live/book_execute.py --execute; rc=$? + [ $rc -eq 75 ] && echo " book: SALTATO — conto occupato da un altro giro (logs/.conto.lock)" # Libro di bordo: materializza in data/live/trades.db (che il backup COPRE) l'ora vera dei # fill, che altrimenti vive solo in questo log — gitignored, fuori dal backup e ruotabile. - # Va DOPO book_execute: dentro lo stesso blocco vede le righe appena scritte. + # Va DOPO book_execute: dentro lo stesso blocco vede le righe appena scritte. Fuori dal lock: + # e' sola lettura, non tocca il conto. uv run python scripts/live/trades_db.py --sync --quiet || true echo "===== done $(date -u '+%H:%M:%SZ') =====" } >> logs/cron_book.log 2>&1 diff --git a/scripts/cron_cuscino.sh b/scripts/cron_cuscino.sh index a48a828..b95ecbf 100755 --- a/scripts/cron_cuscino.sh +++ b/scripts/cron_cuscino.sh @@ -5,11 +5,19 @@ # PUO' INVIARE ORDINI: sotto zero di slack lancia usde_convert --esegui (vende USDE), con le # guardie dichiarate nel docstring di scripts/live/cuscino_watch.py; lo interruttore e' lo # stesso del libro (execution_enabled in config/live.json). +# LOCK SUL CONTO (#36): cuscino_watch e book_execute (cron_book.sh, :47) sono separati solo dal +# tempo e possono mandare ordini sullo stesso conto — giri fino a 659s sono stati misurati. +# `flock -n` (mai `-w`: un'attesa farebbe scivolare il giro orario) su logs/.conto.lock: se +# book_execute lo tiene, questo giro si SALTA (rc 75) invece di sovrapporsi. export PATH="/home/adriano/.local/bin:$PATH" cd /opt/docker/PythagorasGoal || exit 1 mkdir -p logs { echo "===== $(date -u '+%Y-%m-%dT%H:%M:%SZ') cron_cuscino =====" - uv run python scripts/live/cuscino_watch.py --quiet || true + flock -n -E 75 logs/.conto.lock uv run python scripts/live/cuscino_watch.py --quiet; rc=$? + [ $rc -eq 75 ] && echo " cuscino: SALTATO — conto occupato (logs/.conto.lock)" + # (#30) giro orario dei sorveglianti a max_age<=6h: notifica solo il NUOVO, marcatore in + # data/live/monitor_health_detto.json. Fuori dal lock: e' sola lettura, non tocca il conto. + uv run python scripts/live/monitor_health.py --quiet --solo-orari || true echo "===== done $(date -u '+%H:%M:%SZ') =====" } >> logs/cron_cuscino.log 2>&1 diff --git a/scripts/live/usde_convert.py b/scripts/live/usde_convert.py index 2fa07cb..aa92296 100644 --- a/scripts/live/usde_convert.py +++ b/scripts/live/usde_convert.py @@ -61,6 +61,18 @@ reazione sbagliata al sintomo giusto: consuma i tentativi senza toccare la causa uv run python scripts/live/usde_convert.py --quota 0.64 # piano, nessun ordine (0,64 = bersaglio di cuscino_watch) uv run python scripts/live/usde_convert.py --quota 0.64 --esegui # manda l'ordine + +LOCK SUL CONTO (#36). Un lancio a MANO con --esegui condivide il conto con cuscino_watch e +book_execute (cron_cuscino.sh/cron_book.sh, entrambi dentro `flock -n logs/.conto.lock`): senza +lo stesso lock un ordine a mano nello stesso minuto del cron puo' convertire due volte verso +bersagli diversi (limite D5 gia' dichiarato sopra). Si lancia quindi con: + + flock logs/.conto.lock uv run python scripts/live/usde_convert.py --quota 0.64 --esegui + +⚠️ Qui NON senza `-n`: un lancio a mano puo' aspettare il turno invece di saltare. Questo script +stesso NON prende il lock (vedi cuscino_watch.py): se lo facesse e girasse come figlio di +cuscino_watch (che il lock lo tiene gia'), un secondo `flock -n` lo troverebbe occupato e +fallirebbe subito, per costruzione, ogni singola volta. """ from __future__ import annotations