14.3.2. A watchdog¶
A hardveres watchdog az az alap, amelyen minden más megerősítési döntés nyugszik. Ez egy apró, független időzítő, amely visszaállítja a processzort, ha túl sokáig nem kap más utasítást. Egy szkript, amely beragad egy megbízhatatlan érzékelőn, egy hálózati hívás, amely túllépi az időkorlátját, egy memóriafoglaló, amely beragad a halom egy sarkába, egy kivétel, amely megszökött a ciklusból – egyik sem állítja meg a watchdogot. Az időzítő ettől függetlenül számol visszafelé, és a kamera újraindul.
Egy leszállított termék esetében a watchdog nem opcionális. Nélküle a fenti meghibásodási módok bármelyike halott állapotban hagyja a kamerát, amíg valaki észre nem veszi és újra nem indítja az áramellátást. Vele a kamera magától visszatér, és a meghibásodás egyetlen bizonyítéka egy sor a naplóban.
Lásd még
A hardver fejezet watchdog időzítő oldala azt tárgyalja, mi a watchdog hardver szinten, és a machine.WDT API alapjait. Ez az oldal azt tárgyalja, mi változik egy gyártási telepítés esetén.
14.3.2.1. A watchdog elindítása¶
A machine.WDT az API. Hardveresen támogatott: a létrehozása után az időzítő a következő visszaállításig fut. Nincs stop(), nincs deinit(), nincs Ctrl-C kilépés. Ez a lényeg.
Egy tipikus beállítás a main.py tetején, közvetlenül az általa védett ciklus előtt:
from machine import WDT
wdt = WDT(timeout=10_000) # milliseconds
A main.py a megfelelő hely a watchdog számára, mert ott él a ciklus. A watchdog visszaállítás hardveres visszaállítás, így a hidegindítási útvonal újrafut, és a main.py magától újra belép a ciklusba – a helyreállítás működik a boot.py bármilyen vezetékezése nélkül. A watchdog elindítása a boot.py-ban ehelyett azt jelenti, hogy minden szoftveres visszaállítás (egy fejlesztő Ctrl-D billentyűkombinációja például) egy hardveres időzítőt ad az alkalmazásnak, amelyet semmilyen módon nem tud leállítani, ami bosszúság a munkapadon és csapda a gyártási beállító kódban, amely a ciklus készenléte előtt fut.
Válassza meg az időkorlátot úgy, hogy 2-3-szor hosszabb legyen, mint a fő ciklus legrosszabb megfigyelt iterációs ideje. A képkockasebesség ingadozása, egy hideg érzékelő lassú olvasása, egy rövid Wi-Fi akadozás – ezek egyike sem szabad, hogy aktiválja a watchdogot. Egy valódi beakadásnak (egy végtelen ciklus, egy blokkolt I/O hívás) viszont kell. A túl rövid időkorlátok a watchdogot téves visszaállítások forrásává teszik; a túl hosszú időkorlátok hagyják, hogy a kamera percekig válasz nélkül üljön, mielőtt a helyreállítás bekapcsol.
14.3.2.2. A watchdog etetése¶
A wdt.feed() visszaállítja a visszaszámlálót. Hívja meg egyszer a fő ciklus minden iterációjában, a ciklustörzs tetején, hogy az etetés feltétel nélkül megtörténjen minden olyan munka előtt, amely beakadhat:
while True:
wdt.feed()
frame = csi0.snapshot()
process(frame)
14.3.2.3. Kivételek túlélése¶
A watchdog a beakadásokat kezeli. A kivételek más meghibásodási mód. Egy kezeletlen kivétel felbuborékol a szkript legfelső szintjére, a main.py kilép, és a kamera leesik a REPL-be. A watchdog ezután aktiválódik az időkorlátja után, mert semmi sem eteti a REPL-ből, a kamera visszaáll, és a main.py újra fut – tehát a helyreállítás működik, de a terepen minden összeomlásért egy teljes időkorlátot plusz újraindítást fizetnek, a visszakövetés a USB stdout-ra megy, amelyet semmi sem olvas, és minden memóriabeli állapot, amelyet az alkalmazás megtartott, elveszik.
A fő ciklus becsomagolása egy legfelső szintű try / except blokkba egy összeomlást olyan naplózott eseménnyé alakít, amelyen az alkalmazás továbbhalad, anélkül, hogy egy visszaállításért fizetne:
import logging
log = logging.getLogger(__name__)
while True:
wdt.feed()
try:
frame = csi0.snapshot()
process(frame)
except Exception:
log.exception("frame loop iteration failed")
Az Exception (nem a BaseException) elkapása működésben tartja a KeyboardInterrupt és a SystemExit kivételeket, ami az, amit egy USB-n keresztül csatlakozó fejlesztő szeretne.
Ez a minta a folyamatos működés szoftveres fele: a watchdog elkapja a beakadásokat, a csomagoló elkapja az összeomlásokat, és a napló rögzíti, amit bármelyikük elkapott.
14.3.2.4. Annak ismerete, miért történt egy indítás¶
Minden szoftveres visszaállítás és minden watchdog visszaállítás végül friss indításként jelenik meg. Az indításidejű diagnosztikai segédprogram minden hidegindításkor naplózza a machine.reset_cause() értékét; a reset cause sor az, ami megmondja a terepen, hogy a helyreállítás valóban bekapcsolt-e, szemben azzal, hogy a kamera csak normálisan újraindult az áramellátással.
A reset-cause sor az, ami láthatóvá teszi a watchdog munkáját a naplóban. Egy watchdog timeout visszaállításokkal teli napló azt mondja, hogy az alkalmazás beakadt, és a watchdog helyreállította azt. Egy ezek nélküli napló azt mondja, hogy a watchdognak nem kellett aktiválódnia – ami általában azt jelenti, hogy az alkalmazás egészséges, de azt is jelentheti, hogy az időkorlát túl hosszúra van állítva ahhoz, hogy elkapja a ténylegesen előforduló beakadásokat.
14.3.2.5. Egy teljes kezdő váz¶
Egy main.py, amely összefogja a watchdogot, a naplózás beállítását, az indításidejű diagnosztikát és a csomagolót, így néz ki:
import logging
from machine import WDT
from app.logging_setup import setup_logging, log_boot_diagnostics
setup_logging('/sdcard/logs/app.log')
log_boot_diagnostics()
log = logging.getLogger(__name__)
wdt = WDT(timeout=10_000)
while True:
wdt.feed()
try:
step()
except Exception:
log.exception("loop iteration failed")
A step() az alkalmazás iterációnkénti munkája; a váz többi része nem változik a termékek között. A megerősítés egy watchdog, egy csomagoló és egy naplózott indítás minden hidegindításkor – nem sok kód, és ez a különbség egy magától helyreálló kamera és egy szervizhívást igénylő kamera között.