14.3.2. Watchdog¶
Watchdog phần cứng là nền tảng mà mọi lựa chọn hardening khác đặt lên. Đó là một bộ định thời độc lập nhỏ bé đặt lại bộ xử lý khi nó không được thông báo khác trong thời gian quá lâu. Một tập lệnh bị kẹt trên một cảm biến không ổn định, một cuộc gọi mạng bị chặn qua thời gian chờ, một bộ cấp phát bộ nhớ bị mắc kẹt ở một góc của heap, một ngoại lệ thoát ra khỏi vòng lặp -- không có gì trong số đó dừng watchdog. Bộ định thời đếm ngược bất kể, và camera khởi động lại.
Đối với một sản phẩm được giao hàng, watchdog không phải là tùy chọn. Nếu không có nó, bất kỳ chế độ lỗi nào ở trên đều khiến camera chết cho đến khi ai đó nhận ra và tắt/bật nguồn. Với nó, camera tự khởi động lại và bằng chứng duy nhất về sự cố là một dòng trong log.
Xem thêm
Trang watchdog timer trong chương phần cứng đề cập đến watchdog là gì ở cấp độ phần cứng và những điều cơ bản của API machine.WDT. Trang này đề cập đến những gì thay đổi cho một triển khai production.
14.3.2.1. Khởi động watchdog¶
machine.WDT là API. Nó được hỗ trợ bởi phần cứng: một khi được khởi tạo, bộ định thời chạy cho đến lần đặt lại tiếp theo. Không có stop(), không có deinit(), không có lối thoát Ctrl-C. Đó chính là điểm mấu chốt.
Thiết lập điển hình ở đầu main.py, ngay trước vòng lặp mà nó bảo vệ:
from machine import WDT
wdt = WDT(timeout=10_000) # milliseconds
main.py là nơi phù hợp cho watchdog vì đó là nơi vòng lặp tồn tại. Một lần đặt lại watchdog là một lần đặt lại phần cứng, vì vậy đường dẫn khởi động nguội chạy lại và main.py tự vào lại vòng lặp -- quá trình phục hồi hoạt động mà không cần bất kỳ kết nối nào trong boot.py. Thay vào đó khởi động watchdog trong boot.py có nghĩa là mỗi lần soft reset (ví dụ Ctrl-D của nhà phát triển) trao cho ứng dụng một bộ định thời phần cứng không có cách nào dừng lại, đây là sự bất tiện tại bàn làm việc và là bẫy trong mã thiết lập production chạy trước khi vòng lặp sẵn sàng.
Chọn thời gian chờ sao cho dài hơn 2 đến 3 lần so với thời gian lặp được quan sát tệ nhất của vòng lặp chính. Jitter tốc độ khung hình, đọc cảm biến chậm trên cảm biến lạnh, sự gián đoạn Wi-Fi ngắn -- không ai trong số đó nên kích hoạt watchdog. Một lần treo thực sự (vòng lặp vô tận, cuộc gọi I/O bị chặn) thì nên. Thời gian chờ quá ngắn biến watchdog thành nguồn đặt lại giả; thời gian chờ quá dài cho phép camera ngồi không phản hồi trong nhiều phút trước khi quá trình phục hồi kích hoạt.
14.3.2.2. Cấp dưỡng cho nó¶
wdt.feed() đặt lại bộ đếm ngược. Gọi nó một lần cho mỗi lần lặp của vòng lặp chính, ở đầu phần thân vòng lặp để việc cấp dưỡng xảy ra vô điều kiện trước bất kỳ công việc nào có thể bị treo:
while True:
wdt.feed()
frame = csi0.snapshot()
process(frame)
14.3.2.3. Sống sót qua các ngoại lệ¶
Watchdog xử lý các trường hợp treo. Ngoại lệ là một chế độ lỗi khác. Một ngoại lệ không được xử lý nổi lên đến cấp cao nhất của tập lệnh, main.py thoát ra, và camera rơi xuống REPL. Sau đó watchdog kích hoạt sau thời gian chờ vì không có gì cấp dưỡng cho nó từ REPL, camera đặt lại, và main.py chạy lại -- vì vậy quá trình phục hồi có hoạt động, nhưng thực địa phải trả một lần đặt lại đầy đủ thời gian chờ cho mỗi lần crash, traceback đi đến USB stdout mà không có gì đọc, và bất kỳ trạng thái trong bộ nhớ nào mà ứng dụng đang giữ đều biến mất.
Bọc vòng lặp chính trong một try / except cấp cao nhất biến một lần crash thành một sự kiện được ghi nhật ký mà ứng dụng tiếp tục thông qua, mà không phải trả chi phí đặt lại:
import logging
log = logging.getLogger(__name__)
while True:
wdt.feed()
try:
frame = csi0.snapshot()
process(frame)
except Exception:
log.exception("frame loop iteration failed")
Bắt Exception (không phải BaseException) giữ KeyboardInterrupt và SystemExit hoạt động, đó là những gì nhà phát triển kết nối qua USB muốn.
Mẫu này là nửa phần mềm của liveness: watchdog bắt các trường hợp treo, wrapper bắt các crash, và log ghi lại những gì một trong hai bắt được.
14.3.2.4. Biết tại sao một lần khởi động xảy ra¶
Mỗi soft reset và mỗi lần đặt lại watchdog cuối cùng xuất hiện như một lần khởi động mới. Trợ lý diagnostics thời điểm khởi động ghi lại machine.reset_cause() ở mỗi lần khởi động nguội; dòng reset cause là thứ cho biết thực địa liệu quá trình phục hồi có thực sự kích hoạt hay camera chỉ đang tắt/bật nguồn bình thường.
Dòng reset-cause là thứ làm cho công việc của watchdog hiển thị trong log. Một log đầy các lần đặt lại watchdog timeout cho biết ứng dụng đã bị treo và watchdog đã phục hồi nó. Một log không có chúng cho biết watchdog chưa phải kích hoạt -- thường có nghĩa là ứng dụng ổn, nhưng cũng có thể có nghĩa là thời gian chờ được đặt quá dài để bắt các trường hợp treo thực sự đang xảy ra.
14.3.2.5. Một khởi đầu hoàn chỉnh¶
Một main.py kết hợp watchdog, thiết lập logging, diagnostics thời điểm khởi động và wrapper trông như sau:
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")
step() là công việc mỗi lần lặp của ứng dụng; phần còn lại của scaffold này không thay đổi giữa các sản phẩm. Hardening là một watchdog, một wrapper và một lần khởi động được ghi nhật ký mỗi lần khởi động nguội -- không nhiều mã, và đó là sự khác biệt giữa một camera tự phục hồi và một camera cần cuộc gọi bảo trì.