Checkpoint: Error handling và concurrency
Quiz
- Trong một hàm chuyển tiền, vì sao dùng `expect("balance overflow")` sau khi đã trừ tiền ở tài khoản nguồn lại nguy hiểm hơn trả về `Result`?
- Vì `Result` tự động rollback state khi trả `Err`.
- Vì `expect` chậm hơn `Result` nên làm giảm throughput của service.
- Vì panic làm chương trình dừng giữa giao dịch, tiền đã bị trừ mà không có bút toán đối ứng, và caller không thấy khả năng lỗi trong signature.
- Vì `expect` chỉ chạy được trong debug build, release build sẽ bỏ qua kiểm tra.
- Với tiền lưu bằng `i64` cents, điều gì xảy ra với phép cộng bị overflow trong release build mặc định?
- Chương trình panic ngay tại phép cộng.
- Giá trị wrap âm thầm, sai mà không báo, nguy hiểm hơn panic.
- Compiler tự chuyển sang `checked_add`.
- Giá trị bị bão hòa ở `i64::MAX`.
- Lỗi `InsufficientFunds` nên được phân loại và xử lý thế nào?
- Lỗi hệ thống: retry có backoff, trả 503, alert on-call.
- Lỗi nghiệp vụ: trả 422, không retry, không alert on-call, log mức info/warn.
- Lỗi nghiệp vụ nhưng vẫn retry vì có thể khách hàng nạp tiền vào sau.
- Lỗi hệ thống nhưng trả 400 để tránh lộ chi tiết.
- Vì sao không được dùng `anyhow::Error` làm kiểu lỗi trong domain crate?
- Vì `anyhow` chỉ dùng được trong test.
- Vì `anyhow::Error` làm mất khả năng `match` từng variant, phá vỡ hợp đồng kiểu của domain.
- Vì `anyhow` không hỗ trợ async.
- Vì `anyhow::Error` không implement `Debug`.
- Một `async fn` trong Rust khi được gọi thì điều gì xảy ra?
- Tokio tự động spawn nó lên một worker thread.
- Nó chạy đồng bộ và trả về giá trị cuối cùng.
- Thân hàm chạy ngay trên thread hiện tại cho tới `.await` đầu tiên.
- Nó trả về một Future lazy, chưa chạy gì cho tới khi được `.await` hoặc spawn lên runtime.
- Khi chuyển tiền hai chiều giữa tài khoản 1 và 2 bằng nhiều task, cách nào phòng deadlock đúng?
- Lock tài khoản nguồn trước rồi tới tài khoản đích, theo đúng chiều giao dịch.
- Giữ lock lâu hơn để chắc chắn giao dịch hoàn tất trước task khác.
- Dùng `try_lock` và bỏ qua giao dịch nếu không lấy được lock.
- Luôn lock theo thứ tự account id tăng dần, bất kể chiều giao dịch.
- Vì sao giữ guard của `std::sync::Mutex` qua một `.await` là lỗi cần tránh?
- Vì nó gây panic ngay khi guard bị drop.
- Vì nó làm future mất `Send` và `tokio::spawn` từ chối biên dịch; nếu buộc phải giữ lock qua await thì dùng `tokio::sync::Mutex`.
- Vì nó làm mất dữ liệu trong `HashMap` được bảo vệ.
- Vì `std::sync::Mutex` không hỗ trợ đa luồng.
- Toán tử `?` desugar thành `match`; ở nhánh `Err`, nó gọi `From::from` để chuyển đổi kiểu lỗi. Vì vậy `?` chỉ biên dịch được khi đã có impl của trait ____ cho kiểu lỗi đích.
- Để nhiều task cùng sở hữu state, ta bọc state trong `Arc`. Để ghi an toàn khi đọc nhiều ghi ít, ta bọc thêm ____ (tên kiểu lock).
- Hãy tự đánh giá khả năng viết một luồng chuyển tiền async trả `Result`, không panic và không deadlock dưới tải đồng thời. Bạn đã làm được tới đâu?
Sign in to submit answers.