Vai al contenuto
SIMONE PIZZI
Progetti ↗
Runtime TelegramBot Desktop Titan Edition

Titan Blue v2.0.1 e v2.0.2: due hotfix dopo il silenzio

Una race condition nel silenzio notturno e un auto-updater rotto da sempre: i due hotfix che Titan Blue non si aspettava.

Data
Lettura
5 minuti
Sezioni
4
Copertina: Titan Blue v2.0.1 e v2.0.2: due hotfix dopo il silenzio

Wild Coding · 11 Maggio 2026

La v2.0.0 era uscita il 29 aprile. Runtime TelegramBot Titan Edition, oggi più noto come Titan Blue: colore deciso, identità netta, due mesi di patch alle spalle. Avevo scritto che il codice era abbastanza pulito da permettersi di pensare all'estetica. Ci credevo davvero.

Poi è arrivato lunedì mattina.


Il doppio silenzio

A volte i bug non arrivano durante lo sviluppo. Arrivano quando smetti di cercarli.

Alle 6:15 del mattino, il bot di Runtime Radio ha pubblicato il nuovo episodio di TechnoPillz. Operazione normale. Alle 6:16 l'ha pubblicato di nuovo. Alle 6:32, sul canale TechnoPillz Riot, la stessa sequenza: Il Tiralinee, due volte, a distanza di sessantasei secondi.

Non era un loop. Non era un feed impazzito. Era qualcosa di più sottile — qualcosa che esisteva nel codice da quando avevamo introdotto la SilentGuard nella v1.10.7, e che fino a quel momento aveva aspettato la condizione giusta per manifestarsi.

La condizione giusta è: un podcast che esce domenica notte, esattamente dentro la finestra di silenzio.


La collisione che avviene all'alba

Il meccanismo di checkLoop — il ciclo centrale del motore — esegue drainPendingQueue() prima del loop sui feed. La logica è corretta in linea di principio: prima recuperi quello che era stato accantonato durante le quiet hours, poi scansioni i feed per le novità.

Il problema è nella sequenza precisa di quello che succede dopo il drain.

drainPendingQueue() preleva gli item dalla coda persistente e li inserisce in publishQueue — la coda di invio in memoria. Ma non li marca in history. La marcatura avviene solo dentro processPublishQueue(), dopo che Telegram ha confermato il messaggio. Quel momento non è ancora arrivato.

Nell'intervallo tra il drain e l'invio effettivo, processFeed() scansiona gli stessi feed RSS. Trova quegli item. Controlla isProcessed(). Risposta: false — perché nessuno li ha ancora marcati. Li accoda una seconda volta.

processPublishQueue() non aveva un guard contro la deduplicazione interna alla coda. Spediva tutto quello che trovava, nell'ordine in cui era arrivato. Entrambe le copie uscivano su Telegram.

Il bug era silenzioso per una ragione precisa: si manifestava solo quando un item nuovo arrivava durante le quiet hours, e quando drain e processFeed collidevano su quell'item nel primo ciclo utile dopo la fine del silenzio. TechnoPillz e Il Tiralinee escono domenica sera. Le quiet hours finiscono lunedì mattina presto. La collisione era praticamente garantita ogni settimana — solo che per settimane non avevo guardato i log all'alba di lunedì.

Il fix è in processPublishQueue(). Prima di ogni invio, ora c'è un controllo isProcessed(): se l'item è già stato marcato da un job precedente della stessa coppia, il secondo job viene scartato con log ⏭️ Skip duplicato in coda. Il guard non è all'ingresso della coda ma all'uscita — perché è lì, nell'istante prima dell'invio, che si ha la certezza di cosa è già stato fatto.

Ho sistemato anche una piccola cosa collaterale: il log 🌙 salvato in coda persistente appariva ad ogni ciclo di quiet hours per lo stesso item, anche quando l'INSERT OR IGNORE lo rigettava in silenzio. Adesso addToPendingQueue() restituisce un boolean che indica se l'inserimento è stato effettivo, e il messaggio appare solo quando c'è qualcosa da annunciare.

Questa versione si chiama v2.0.1.


L'updater che non aggiornava

Mentre verificavo che la v2.0.1 si distribuisse tramite auto-updater, ho scoperto che l'auto-updater non funzionava. Non dalla v2.0.1. Da prima. Probabilmente da sempre.

Il meccanismo è questo: quando electron-builder compila una release, genera un file latest.yml con il nome del pacchetto da scaricare. L'artifactName era definito usando ${productName}, che vale "Runtime Telegram Bot Titan Edition" — con tutti gli spazi.

electron-builder, nel generare il latest.yml, converte quegli spazi in trattini. Il file dice:

Runtime-Telegram-Bot-Titan-Edition-Setup-2.0.1.exe

GitHub Releases, quando riceve l'asset, converte quegli stessi spazi in punti. L'asset viene salvato come:

Runtime.Telegram.Bot.Titan.Edition-Setup-2.0.1.exe

electron-updater legge il latest.yml, cerca il file con i trattini, non lo trova. 404, ad ogni aggiornamento, da ogni versione precedente.

I due sistemi usavano la stessa fonte — il productName — e la trattavano in modo incompatibile. Nessuno dei due sbagliava, in senso stretto. La convenzione di electron-builder e quella di GitHub Releases semplicemente non coincidevano, e nessuno aveva mai guardato abbastanza da vicino per accorgersene.

Il fix è in electron-builder.yml, con nomi hardcoded che eliminano l'ambiguità alla radice:

# Windows
RuntimeTelegramBot-TitanEdition-Setup-${version}.${ext}

# Linux e macOS
RuntimeTelegramBot-TitanEdition-${version}.${ext}

latest.yml e asset GitHub ora portano lo stesso nome. Il download OTA funziona.

Questa versione si chiama v2.0.2.


Due hotfix nello stesso giorno

L'11 maggio 2026 è stato un giorno da due hotfix.

Non è una storia edificante sulla bontà del processo di sviluppo. È una storia su come certi bug esistano nel codice per settimane prima che le condizioni giuste li rendano visibili — e su come a volte quelle condizioni siano una domenica sera, dei podcast, e una finestra di silenzio che finisce alle sei di mattina.

La race condition della v2.0.1 era nata insieme alla SilentGuard. Il fix che impediva di perdere item durante le quiet hours aveva creato, nel punto esatto della riapertura, un momento di gara tra due path che scrivevano sulla stessa coda. Il bug era dentro il guard. Il guard proteggeva dall'esterno e non si proteggeva da sé stesso.

Il 404 dell'updater era più vecchio ancora. Ogni release aveva generato il problema, ogni release lo aveva ereditato, e nessuno lo aveva mai trovato perché per trovarlo bisognava aspettare che una versione fosse già installata e tentare un aggiornamento — non testare il build, non leggere i log della compilazione, non guardare il changelog.

Con la v2.0.2 entrambi sono chiusi.

Titan Blue rimane blu. È ancora stabile. Adesso si aggiorna anche da solo.


Lo trovi su Ecosystem.Runtime a 9,99€ una tantum. Windows e Linux.

Ogni tanto scrivo una lettera

Nessuna cadenza fissa, nessun riassunto automatico: parte solo quando ho qualcosa da raccontare. In fondo a ognuna c'è il link per uscire.

↑ Su

Cerca nel sito

Condividi

L'indirizzo di questa pagina:

Scrivi a Simone

Segnalazioni, correzioni, o solo per dire che una cosa non funziona: quest'ultima è la più utile di tutte.