
Turvakontroll, mis muutis meie rakenduse võimatuks sulgeda
Automaatne uuendus oli raskeim funktsioon, mille oleme kunagi välja lasknud — kuus väljalaset nelja päevaga, et takistada sel rakendust nurjata. Halvim viga oli see, mille tõime sisse ettevaatlikkusest: 500-millisekundiline "turva"-kontroll, mis muutis ebaõnnestunud uuenduse protsessiks, mida sa sõna otseses mõttes ei saanud sulgeda.
Iga töölauarakenduse arendaja alahindab automaatset uuendust täpselt üks kord. See tundub lahendatud probleemina — teek laadib alla uue versiooni ja taaskäivitab su rakenduse. Siis lased selle välja ja saad teada, et "taaskäivita oma rakendus" on üks ohtlikumaid asju, mida programmilt saab paluda, sest see juhtub täpselt hetkel, mil su rakendus lammutab iseennast ja tal on kõige väiksem veamarginaal.
GeekBye automaatne uuendus vajas stabiliseerumiseks kuut väljalaset nelja päevaga — v1.5.14 kuni v1.5.19. See on lugu selle lõigu halvimast veast, mille põhjustasime ise, üritades olla ettevaatlikud.
Kuus väljalaset ja see üks, millel oli tähtsust
Kaar algas argiselt. v1.5.14 parandas piinliku trükiviga-tüüpi vea: uuendusvoog osutas GitHubi repositooriumi nimele, mida polnud olemas, nii et uuendaja kontrollis 404-t. v1.5.15 lisas käsitsi nupu "Check for Updates" ja päris veateate. Siis algasid quitAndInstalli vead ja väljalasked tulid kiiresti — sest kui su uuendusmehhanism on katki, ei saa sa selle parandust välja lasta läbi uuendusmehhanismi. Iga iteratsioon on käsitsi taasinstallimise hasartmäng.
See, millel on tähtsust, on v1.5.18. Selle kogu sisu oli üks commit pealkirjaga, mille peale ma siiani võpatan: restore original quitAndInstall behavior to prevent unkillable app.
Kuidas "ettevaatlik olemine" rakenduse nurjas
Siin on olukord. Kui uuendus on alla laaditud, peaks Electroni quitAndInstall sulgema rakenduse ja vahetama sisse uue versiooni. Ühes varasemas väljalaskes muretses keegi — põhjendatult —, et tingimusteta sulgemine on riskantne. Mis siis, kui installimine annab vea? Kas poleks turvalisem sulgeda ainult siis, kui kõik näeb terve välja?
Nii kasvatas kood vahi, mis nägi mõistlik välja:
autoUpdater.quitAndInstall(false, true)
setTimeout(() => {
if (this.updateDownloaded)
app.quit() // only quit if the update is still "good"
else console.log('Error detected — keeping app open')
}, 500)
Loogika: käivita installimine, oota pool sekundit ja sunni lõplik app.quit() välja ainult siis, kui lipp updateDownloaded on endiselt tõene — muidu hoia rakendus avatuna, et kasutaja ei jääks hätta.
Lõks on ühe rea kaugusel, veakäsitlejas. See käsitleja seadis this.updateDownloaded = false. Nii et kujuta ette ebaõnnestunud installimist: sündmus error vallandub ja tühjendab lipu. Kuid quitAndInstall oli juba alustanud lammutamist — see oli sulgenud aknad ja eemaldanud rakenduse sulgemiskuulajad. Siis ärkab 500 ms taimer, kontrollib nüüd vale lippu, otsustab "viga tuvastatud, hoia rakendus avatuna" ja jätab app.quit() vahele.
Nüüd on sul, just nimelt macOS-is, halvim võimalik olek. macOS ei sulge rakendust ainult sellepärast, et selle viimane aken sulgus — see on window-all-closed käitumine, millele iga Maci rakendus toetub. Nii et protsess on endiselt elus, kuid sellel pole akent, pole menüüriba teed ja selle sulgemiskuulajad on välja rebitud. Pole midagi, millele klõpsata. Cmd-Q-l pole millegagi rääkida. Ainus väljapääs on Force Quit Activity Monitorist. "Turva"-kontroll oli muutnud ebaõnnestunud uuenduse — taastatava tüli — zombiks, keda sa ei saanud tappa.
Parandus: lammutamine peab olema tingimusteta
Parandus v1.5.18-s on peaaegu agressiivselt igav, ja see ongi mõte. See eemaldab nutikuse:
- Eemalda
window-all-closedjabefore-quitkuulajad, mis võiksid segada. - Hävita iga aken —
window.destroy(), mittewindow.close(). Sulgemist saab käsitleja vetostada; hävitamist ei saa. Kui sa pühendud väljalülitumisele, ei küsi sa viisakalt. - Kutsu
quitAndInstall. - Kutsu
app.quit()tingimusteta.
Ei mingit lippu, ei mingit taimerit, ei mingit "hoia see avatuna igaks juhuks". Sest tõde väljalülitumise tee kohta on see, et poolik väljalülitumine on halvem kui kumbki tulemus. Täielik sulgemine on korras. Täielikult avatuks jäämine on korras. Ainus olek, milleni sa ei tohi kunagi jõuda, on lammutatud, kuid endiselt töötav — ja täpselt sellesse olekusse võib sind tingimuslik sulgemine kinni jätta.
Veel kaks õppetundi, mille sama nädal andis
Suletamatu viga on pealkiri, kuid kuue väljalaske rabelemine karastas kaks muud harjumust, mida tasub varastada.
Filtreeri oma krahhitelemeetriat täpsete allkirjade, mitte laiade märksõnade järgi. Rabelemise keskel avastasime, et meie veateavitus oli seadistatud kõrvale heitma kõike, mis sisaldas sõnu nagu permission, token või microphone — katse müra vähendada, mis vaikselt neelas tõelisi krahhe, mis juhtusid neid sõnu mainima. Rebisime laiad filtrid välja ja asendasime need täpsete keeldumisstringidega (konkreetne teade, mille macOS väljastab, kui luba tagasi lükatakse) ja konkreetsete ajutiste võrgukoodidega nagu ERR_NETWORK_CHANGED. Müra vähendamine ja vigade peitmine on sama nupp, keeratud vastupidistesse suundadesse; kui sa filtreerid tunde järgi, filtreerid välja just selle, mida sul oli vaja näha.
Iga automaatne tee vajab käsitsi pääseteed. Automaatne uuendus on oma olemuselt parimale-pingutusele suunatud — võrgud tõrguvad, installimised ebaõnnestuvad. Nii sai iga tõrkerežiim inimliku varuvariandi: käsitsi nupu "Check for Updates", eksponentsiaalse tagasilibisemisega kordused, taaskontrolli taimeri ja — reserveeritud just juhtumiks, kui kasutaja käsitsi katse ebaõnnestus — lihtsas keeles teate "kustuta rakendus ja installi uuesti veebisaidilt". Automaatne tee on mugavus; käsitsi tee on garantii.
Peamine mõte
- Vaht pöördumatu toimingu ümber on ohtlikum kui toiming ise. Tingimuslik sulgemine üritas takistada halval uuendusel rakendust sulgeda ja tekitas selle asemel oleku, mis on halvem kui sulgemine või mittesulgemine. Väljalülitumise ja installimise teed peaksid olema tingimusteta ja idempotentsed — mitte kunagi seotud muudetava lipuga, mille teine käsitleja saab su alt välja lüüa.
- macOS-is "pole aknaid" ei ole "pole rakendust". Iga lammutusloogika peab arvestama platvormiga, kus aknata protsess töötab edasi. Testi tõrketeed päris operatsioonisüsteemis, mitte ainult õnnelikku teed.
- Funktsiooni, mille lased välja läbi uuendussüsteemi, ei saa testida läbi uuendussüsteemi. See asümmeetria on põhjus, miks automaatne uuendus väärib paranoilist, tingimusteta, tugevalt käsitsi kontrollitud koodi. Sa saad selle lihtsat teed pidi parandada alles pärast seda, kui see juba töötab.
See on töökindluse töö varaseim peatükk, millest lõpuks sai GeekBye v2. Selle kohta, kuhu see tee viis, vaata mida versioon 2 tegelikult nõuab (v2.0.0) ja kogu kaart artiklis tarkvara täiuseni väljalaskmise anatoomia.