
📘 La costruzione del Watcher PRO: un viaggio tecnico nella sincronizzazione tra filesystem, backend Laravel ed Electron
🧭 Introduzione
In questo articolo racconto — in modo tecnico e dettagliato — lo sviluppo del Watcher PRO, un componente fondamentale di un progetto più ampio: un assistente digitale avanzato, capace di monitorare in tempo reale un progetto Flutter/Dart, inviare eventi strutturati a un backend Laravel e sincronizzare la struttura del progetto con un’interfaccia Electron.
Il Watcher PRO è il cuore pulsante del sistema: osserva, interpreta, normalizza e comunica ogni modifica del filesystem, garantendo che l’assistente digitale sia sempre aggiornato sullo stato del progetto.
Quello che segue è il percorso completo:
dalla progettazione iniziale → alla gestione degli eventi → alla scansione iniziale → al batching → alla risoluzione dei problemi → alla stabilizzazione finale.
🏗️ Obiettivo del Watcher PRO
Il Watcher PRO deve:
- monitorare in tempo reale una cartella (la root del progetto Flutter)
- rilevare creazioni, modifiche e cancellazioni di file
- normalizzare i percorsi
- filtrare cartelle irrilevanti (build, .git, .dart_tool…)
- inviare eventi al backend Laravel
- gestire heartbeat periodici
- inviare un batch iniziale con la struttura completa del progetto
- mantenere sincronizzato Electron con la struttura del filesystem
Il tutto con:
- robustezza
- tolleranza agli errori
- assenza di blocchi
- assenza di duplicazioni
- assenza di perdita di eventi
🔍 Architettura del Watcher
Il Watcher PRO è composto da:
1. event_queue
Una coda thread-safe (queue.Queue) dove confluiscono tutti gli eventi:
- eventi del filesystem
- heartbeat
- eventi di startup
- eventi di errore
- eventi della scansione iniziale
- evento “flush” (patch finale)
2. sender_thread
Il thread responsabile dell’invio degli eventi al backend Laravel.
Funzioni principali:
- consuma la coda
- gestisce heartbeat separatamente
- accumula eventi in un buffer
- invia batch ogni 100 ms
- gestisce errori interni
- invia un batch completo quando riceve “flush”
3. heartbeat_thread
Invia un evento “alive” ogni 30 secondi, utile per:
- monitorare lo stato del watcher
- evitare timeout lato backend
- garantire che il watcher sia vivo anche in assenza di modifiche
4. ProEventHandler (Watchdog)
Gestisce gli eventi del filesystem:
on_createdon_modifiedon_deleted
Filtra cartelle ignorate e normalizza i percorsi.
5. initial_scan
Scansiona l’intera root del progetto e genera:
folder_createdper ogni cartellafile_createdper ogni file
Serve a costruire la struttura iniziale del progetto.
6. flush (patch finale)
Un evento artificiale che forza l’invio del batch completo dopo la scansione iniziale.
🧪 Il problema che abbiamo incontrato
Durante lo sviluppo, il Watcher PRO funzionava perfettamente:
- rilevava eventi
- inviava heartbeat
- inviava batch
- sincronizzava Electron
- popolava
project_structure.json
Poi, improvvisamente:
- heartbeat continuava a funzionare
- la scansione iniziale veniva eseguita
- gli eventi venivano generati
- il sender_thread riceveva gli eventi
- ma nessun batch veniva inviato
Laravel mostrava:
Batch check: {"has_batch":false}
Electron non riceveva nulla.
La struttura non veniva aggiornata.
🧩 Diagnosi tecnica
Grazie a una riga di debug aggiunta nel punto giusto:
print("[DEBUG] Evento nel sender_thread:", event)
abbiamo scoperto che:
- il sender_thread riceveva correttamente tutti gli eventi
- il buffer si riempiva
- ma il batch non scattava mai
Perché?
🔥 Perché gli eventi della scansione iniziale arrivavano troppo velocemente.
Il batching era basato su:
if time.time() - last_send > 0.1:
Ma:
- centinaia di eventi arrivavano in meno di 100 ms
- il timer non scattava
- il batch non veniva inviato
- il buffer non veniva svuotato
- Laravel non riceveva nulla
🛠️ La soluzione: evento “flush”
Abbiamo introdotto un evento artificiale:
event_queue.put({"type": "flush"})
inviato subito dopo la scansione iniziale.
E nel sender_thread:
if event.get("type") == "flush":
if buffer:
send_event({"batch": buffer})
buffer = []
event_queue.task_done()
continue
Questo:
- forza l’invio del batch completo
- svuota il buffer
- sincronizza Laravel
- sincronizza Electron
- ripristina il comportamento originale del watcher
🚀 Risultato finale
Electron ha mostrato:
[Watcher] batch_summary — batch:334
Laravel ha ricevuto la struttura completa.
project_structure.json è stato popolato.
Il watcher è tornato stabile e affidabile.
📦 Stato attuale del Watcher PRO
Oggi il Watcher PRO:
- monitora correttamente il filesystem
- invia heartbeat regolari
- gestisce errori interni
- invia batch ogni 100 ms
- invia un batch completo iniziale tramite flush
- mantiene sincronizzato Laravel
- mantiene sincronizzato Electron
- è robusto, stabile e pronto per essere integrato nell’assistente digitale
🔮 Prossimi passi
In futuro potremo:
- ottimizzare il flush (solo se necessario)
- ridurre la frequenza dei batch
- introdurre un sistema di differenze (diff)
- aggiungere un watcher per i file di configurazione
- integrare un sistema di caching
- collegare il watcher al motore di analisi del codice dell’assistente digitale
🏁 Conclusione
Il Watcher PRO è ora un componente solido, affidabile e pronto per essere integrato nel sistema più grande: un assistente digitale capace di comprendere il progetto Flutter, analizzarlo, proporre refactoring, generare codice e mantenere una memoria contestuale.
Questo articolo racconta l’intero percorso:
dalla progettazione → al problema → alla diagnosi → alla soluzione → alla stabilizzazione.
credit: sistema sviluppato con assistenza tecnica di Microsoft Copilot
📚 Bibliografia essenziale per la realizzazione di un Watcher in Python
La costruzione di un watcher affidabile in Python richiede la comprensione di alcuni strumenti fondamentali: il modulo watchdog, la gestione dei thread, le code FIFO (queue.Queue) e le tecniche di batching.
Di seguito una selezione di risorse essenziali, autorevoli e direttamente utili allo sviluppo del Watcher PRO.
🔹 Documentazione ufficiale Watchdog
Watchdog — Python API Documentation
https://python-watchdog.readthedocs.io/en/stable/
La risorsa più importante.
Contiene:
- API complete di
ObservereFileSystemEventHandler - esempi di implementazione
- gestione dei thread interni
- note sulle differenze tra OS (Windows, macOS, Linux)
- limitazioni note del backend di Watchdog
🔹 Repository ufficiale su GitHub
Watchdog GitHub Repository
https://github.com/gorakhargosh/watchdog
Utile per:
- leggere il codice sorgente
- comprendere il comportamento interno degli observer
- verificare issue note e bug reali
- studiare esempi avanzati non presenti nella documentazione
🔹 Python Threading (documentazione ufficiale)
Threading — Python Standard Library
https://docs.python.org/3/library/threading.html
Fondamentale per:
- comprendere la gestione dei thread del watcher
- evitare deadlock
- gestire correttamente thread multipli (sender, heartbeat, observer)
- capire come funziona
daemon=True
🔹 Python Queue (documentazione ufficiale)
Queue — Python Standard Library
https://docs.python.org/3/library/queue.html
Indispensabile per:
- implementare una coda thread-safe
- evitare race condition
- gestire correttamente
put(),get(),task_done() - costruire un sistema di batching affidabile
🔹 Requests — HTTP client per Python
Requests Documentation
https://requests.readthedocs.io/en/latest/
Utile per:
- inviare eventi al backend Laravel
- gestire errori di rete
- implementare retry e timeout
- costruire payload JSON robusti
🔹 Esempio di batching manuale (concetto base)
Il batching del Watcher PRO si basa su un pattern simile a questo:
import queue, time
event_queue = queue.Queue()
buffer = []
last_send = time.time()
while True:
event = event_queue.get()
buffer.append(event)
if time.time() - last_send > 0.1:
print("Invio batch:", buffer)
buffer = []
last_send = time.time()
event_queue.task_done()
Questo esempio mostra:
il concetto di buffer
il timer per l’invio
la gestione della coda
la logica di batching
Il Watcher PRO implementa una versione molto più avanzata, con:
heartbeat
flush
gestione errori
thread multipli
normalizzazione dei path
filtraggio delle directory
integrazione con Laravel ed Electron