Profile
Quỳnh thích tối ưu
Author
Quỳnh Ruby quynhthichtoiuu.com
Author
Quỳnh Ruby quynhthichtoiuu.com
Author
Quỳnh Ruby quynhthichtoiuu.com

Webhook báo "thành công", nhưng database trống trơn

Sau khi sắp xếp lại 47 bài viết cũ theo nhóm mới, mình push lên, hồ hởi mở trang dự án ra xem timeline. Trống trơn. "Chưa có bài viết nào."

Lạ ở chỗ: mọi thứ đều báo thành công. Đây là bài ghi lại một tiếng đồng hồ đi tìm một con bug giả vờ rằng nó không tồn tại.

Triệu chứng: thành công giả

Blog này lưu nội dung trên Cloudflare D1. Cơ chế: mình push markdown lên GitHub, một webhook bắn sang con worker, worker đọc file rồi ghi vào database.

Mình mở log của webhook ra. Nó trả về 200, kèm synced: 33. Nhìn là biết: 33 file, đồng bộ xong. Đáng lẽ phải vui. Nhưng dữ liệu thì không hề đổi.

Bài học đầu: đừng tin status code, đi xem sự thật

Thay vì ngồi đoán, mình đi kiểm chứng bằng thứ thật nhất — trang đang chạy. Mở thẳng đường dẫn category mới trên production: 404. Mở category cũ: vẫn còn nguyên mấy bài đáng lẽ đã chuyển đi.

Kết luận lạnh người: database chưa thay đổi gì cả. Cái 200 · synced: 33 kia là một lời nói dối.

Manh mối nằm trong một chữ "false"

Mình đọc kỹ lại cái response. Có một dòng: indexesRebuilt: false.

Đối chiếu với code: con số synced chỉ đếm số file có trong gói webhook — không phải số bản ghi thực sự được viết. Còn indexesRebuilt mới là cờ báo "có ghi được cái gì không". Nó là false. Tức là: nhận 33 file, ghi được 0.

Một con số đếm "đã nhận" mà mình tưởng là "đã làm xong". Đó là cái bẫy.

Manh mối thứ hai: cái gì vẫn chạy

Mình để ý: mấy bài mình đăng nhanh qua Telegram thì vẫn lên bình thường. Chỉ bài push qua git mới hỏng.

Hai con đường này khác nhau ở một điểm: Telegram đẩy thẳng nội dung vào, còn git thì worker phải tự đi đọc file từ repo — mà repo này để riêng tư. Đọc repo riêng tư thì cần một cái token.

Đến đây thì lộ. Cái token đó đã hết hạn. Mỗi lần worker đi đọc file, GitHub trả về 401. Worker nuốt gọn cái lỗi đó, trả null, bỏ qua file — rồi vẫn thản nhiên báo 200 ra ngoài.

Cái mình sửa không chỉ là cái token

Thay token mới thì 33 bài vào database ngay. Nhưng mình dừng lại lâu hơn ở một câu hỏi: vì sao một thất bại toàn tập lại trông như thành công?

Nên mình sửa luôn con webhook: nếu có file cần đọc mà ghi được con số 0, nó phải báo lỗi to — trả về mã lỗi thật kèm gợi ý "token có thể đã hết hạn", để lần giao webhook hiện đỏ lòm trong lịch sử thay vì xanh giả. Một cái 200 dối trá còn nguy hiểm hơn một cái lỗi thật, vì nó khiến mình tin sai trong im lặng.

Mình rút ra gì

  • "Đã nhận" không phải "đã xong". Một metric đếm sai chỗ sẽ nói dối bạn rất tự tin.
  • Verify bằng artifact thật, đừng bằng status code. Trang chạy thật mới là sự thật; 200 chỉ là lời hứa.
  • Lỗi phải ồn ào. Fail lặng lẽ là loại bug đắt nhất — nó giả vờ mọi thứ đều ổn cho tới khi bạn tình cờ phát hiện.

Mình mất gần một tiếng cho một dòng chữ false mà lẽ ra phải đỏ ngay từ đầu. Giờ thì nó đỏ thật.