Làm Cùng Long.
← Quay lại Tản Mạn
Công việc · 11 phút đọc ·

Một lịch tự động chỉ đáng tin khi có bằng chứng nó đã hoàn tất

Một lịch tự động có thể kích hoạt đúng giờ nhưng vẫn thất bại ở bước tạo file, mở PR, gửi dữ liệu hoặc xác nhận đầu ra. Vì vậy, trạng thái đã chạy không nên được dùng thay cho đã hoàn tất.

Minh họa một lịch tự động kích hoạt chuỗi xử lý đi qua các cổng kiểm tra trước khi tạo ra đầu ra đã được xác nhận
Minh họa editorial tạo cho Làm Cùng Long

Có một kiểu lỗi khá khó chịu trong automation: mọi thứ trông như đã chạy, nhưng công việc thực tế vẫn chưa hoàn tất.

Lịch kích hoạt đúng giờ. Hệ thống có một mốc lần chạy gần nhất. Một workflow bắt đầu. Có khi một vài bước đầu còn chạy thành công. Nhìn từ bên ngoài, rất dễ kết luận rằng automation đã làm phần việc của nó.

Nhưng nếu đầu ra cần thiết không xuất hiện, người dùng vẫn đang ở đúng vị trí như trước khi workflow chạy.

Một file chưa được tạo. Một bản ghi chưa được ghi. Một Draft PR chưa được mở. Một cảnh báo chưa được gửi. Một dữ liệu chưa được đọc ngược để xác nhận. Một bước cuối không xảy ra nhưng hệ thống vẫn để lại đủ dấu vết khiến ta có cảm giác “nó đã chạy rồi”.

Điều này làm tôi nghĩ nhiều hơn về một khác biệt tưởng nhỏ nhưng rất quan trọng:

Một workflow được kích hoạt không đồng nghĩa một workflow đã hoàn tất.

Và càng dùng nhiều automation, AI agent, scheduled task hay workflow nối nhiều công cụ, tôi càng thấy trạng thái “Done” cần được định nghĩa bằng bằng chứng đầu ra, không phải bằng tín hiệu từ bước đầu tiên.

Scheduler chỉ chứng minh một việc: thời điểm bắt đầu đã xảy ra

Một lịch chạy tự động thường trả lời câu hỏi khá hẹp:

Đến thời điểm đã định, hệ thống có cố gắng bắt đầu workflow hay không?

Đó là thông tin cần thiết, nhưng chỉ là lớp đầu tiên.

Giả sử một task chạy lúc 8 giờ sáng. Scheduler ghi nhận run lúc 8:00. Nếu chỉ nhìn log lịch, ta có thể nghĩ mọi thứ ổn.

Nhưng từ 8:00 trở đi còn rất nhiều thứ có thể xảy ra: một nguồn dữ liệu không truy cập được; một API trả lỗi; một bước tạo file thất bại; một branch được tạo nhưng bước mở PR không chạy; một output được ghi nhưng sai ngày; một file tồn tại nhưng frontmatter không đúng; một lệnh gửi thông báo không thực hiện; hoặc một workflow tạo xong artifact nhưng không đọc lại để xác nhận.

Trong tất cả các tình huống này, scheduler vẫn có thể nói thật: tôi đã kích hoạt.

Vấn đề nằm ở chỗ chúng ta vô tình đọc câu đó thành: công việc đã hoàn tất.

Hai câu này không giống nhau.

Nếu một quy trình gồm năm bước, bằng chứng ở bước một không thể đại diện cho bước năm.

Tôi muốn tách một automation thành ít nhất năm trạng thái

Để tránh nhầm, tôi thấy hữu ích khi nhìn một automation theo chuỗi:

Scheduled → Started → Executed → Verified → Completed

Scheduled nghĩa là lịch tồn tại và đúng cấu hình.

Started nghĩa là run đã thực sự được kích hoạt.

Executed nghĩa là các hành động chính đã được thực hiện: tạo file, ghi dữ liệu, gọi API, tạo branch, mở PR hay gửi thông báo.

Verified nghĩa là hệ thống đã đọc ngược đầu ra hoặc kiểm tra trạng thái đích để xác nhận thao tác vừa làm tạo ra đúng thứ cần có.

Completed nghĩa là tiêu chí thành công của công việc đã đạt.

Nhiều workflow hiện nay dừng việc quan sát ở lớp Started hoặc Executed.

Một API trả 200 thì coi như xong. Một lệnh tạo file không báo lỗi thì coi như xong. Một automation có thời gian chạy gần nhất thì coi như xong.

Nhưng nếu mục tiêu của workflow là “mỗi ngày có một Draft PR mới”, thì bằng chứng hoàn tất phải là Draft PR thật sự tồn tại, đúng ngày, có đúng file, đúng trạng thái draft và branch còn tồn tại.

Mọi tín hiệu trước đó chỉ là bằng chứng trung gian.

Output contract quan trọng hơn task contract

Một workflow thường được mô tả bằng hành động: lấy dữ liệu, phân tích, viết bài, tạo branch, mở PR.

Nhưng mô tả bằng hành động có một điểm yếu: từng bước có thể “đã chạy” mà mục tiêu cuối vẫn chưa đạt.

Tôi bắt đầu thích cách định nghĩa workflow bằng output contract hơn.

Thay vì chỉ viết:

Mỗi ngày lúc 8 giờ, hãy viết một bài.

Có thể định nghĩa rõ hơn:

Mỗi ngày phải tồn tại đúng một daily slot có article mang ngày local hôm đó, trên branch riêng, draft=true, và có open Draft PR trỏ vào main. Chỉ khi đọc ngược và xác nhận đủ các điều kiện này mới được gọi là CREATED.

Sự khác biệt nghe hơi kỹ thuật, nhưng nó thay đổi cách hệ thống tự đánh giá.

Khi tiêu chí thành công nằm ở đầu ra, workflow buộc phải quan tâm đến bước cuối.

Nếu branch đã có nhưng PR chưa có, trạng thái phải là chưa hoàn tất, không phải “đã viết bài”.

Nếu PR có nhưng article dùng ngày hôm qua, trạng thái phải là date mismatch, không phải “đã có bài”.

Nếu file được tạo nhưng draft=false ngoài ý muốn, workflow chưa đạt contract.

Nếu automation chạy nhưng không còn đầu ra nào có thể kiểm chứng, trạng thái đúng là không có bằng chứng hoàn tất.

Đây là cách biến một quy trình từ “thực hiện thao tác” thành “chứng minh kết quả”.

Read-back là một bước nhỏ nhưng rất đáng giá

Có một thói quen tôi thấy hữu ích trong nhiều hệ thống: sau khi ghi, hãy đọc lại.

Ghi vào Google Sheet thì đọc lại vùng vừa ghi.

Tạo file thì fetch lại file.

Mở PR thì đọc lại trạng thái PR.

Cập nhật frontmatter thì đọc lại chính frontmatter đó.

Gửi event thì kiểm tra log phía nhận.

Tạo lead thì xác nhận lead đã nằm trong nơi cần lưu.

Read-back nghe có vẻ dư thừa vì hệ thống vừa trả về “success”. Nhưng success của thao tác và đúngness của outcome là hai chuyện khác nhau.

Một request có thể thành công về mặt giao thức nhưng payload không đúng. Một file có thể được tạo đúng API nhưng nằm sai branch. Một PR có thể mở được nhưng target sai base. Một dữ liệu có thể ghi được nhưng lệch cột.

Read-back làm tăng một chút thời gian, đổi lại nó giúp hệ thống tự phát hiện nhiều lỗi mà con người thường chỉ nhận ra sau vài giờ hoặc vài ngày.

Với automation quan trọng, tôi không còn xem read-back là bước QA tùy chọn. Nó là một phần của định nghĩa hoàn tất.

Idempotency giúp recovery không tạo thêm lỗi mới

Khi một lịch tự động thất bại, phản xạ thường là “chạy lại”.

Nhưng chạy lại một workflow không có cơ chế nhận diện trạng thái hiện tại rất dễ tạo thêm vấn đề.

Ví dụ bài đã được viết nhưng PR chưa mở, branch đã có, file đã có, chỉ còn thiếu bước cuối.

Nếu recovery không hiểu trạng thái đó, nó có thể viết thêm một bài thứ hai, tạo thêm branch, tạo duplicate content rồi vẫn chưa sửa lỗi gốc.

Một recovery tốt cần hỏi trước:

Phần nào đã tồn tại, phần nào chưa?

Nếu article hôm nay đã có trên branch nhưng thiếu PR, nhiệm vụ recovery chỉ là mở PR còn thiếu.

Nếu PR đã tồn tại và hợp lệ, recovery phải no-op.

Nếu chưa có daily slot, lúc đó mới tạo article mới.

Cách này giúp retry an toàn hơn.

Một workflow đáng tin không chỉ cần biết “làm thế nào khi mọi thứ bình thường”, mà còn cần biết tiếp tục từ trạng thái dang dở mà không nhân đôi đầu ra.

Watchdog không nên chỉ nhìn lịch, mà phải nhìn outcome

Một watchdog tốt không nên hỏi duy nhất:

Task có chạy lúc 8 giờ không?

Câu hỏi quan trọng hơn là:

Đến 10 giờ, outcome mà task phải tạo ra có tồn tại và hợp lệ không?

Nếu mục tiêu là một Draft PR mỗi ngày, watchdog cần nhìn repo.

Nếu mục tiêu là một lead được lưu, watchdog cần nhìn nơi lưu lead.

Nếu mục tiêu là một báo cáo, watchdog cần nhìn file báo cáo.

Nếu mục tiêu là dữ liệu đồng bộ, watchdog cần nhìn freshness và record coverage.

Điểm này khiến watchdog độc lập hơn với pipeline chính.

Nếu cả workflow chính và watchdog cùng tin vào một thời gian chạy gần nhất, chúng có thể cùng kết luận sai theo một cách giống nhau.

Nhưng nếu workflow chính báo “đã chạy” trong khi watchdog đi kiểm tra trực tiếp đầu ra và không thấy gì, sự khác biệt đó chính là tín hiệu cần xử lý.

Nói cách khác, watchdog nên kiểm tra sự thật ở hệ thống đích, không chỉ kiểm tra lời khai của hệ thống nguồn.

Có bài khác hôm nay không nên làm daily workflow tự bỏ cuộc

Có thêm một lỗi logic khá dễ xảy ra với automation nội dung.

Giả sử mục tiêu là mỗi ngày workflow daily phải tạo một bài.

Trong cùng ngày, có thể đã có một bài khác được viết thủ công, một bài repair, một bài backfill hoặc một PR từ ngày trước vừa được merge.

Nếu scheduler chỉ hỏi:

Hôm nay repo đã có bài chưa?

nó có thể tự skip dù daily slot của nó chưa chạy.

Nhìn bề ngoài, website vẫn có hoạt động nội dung. Nhưng contract “daily workflow tạo một bài mỗi ngày” đã bị phá.

Vì vậy, với những quy trình cần cadence rõ, tôi thấy nên có identity riêng cho từng slot.

Ví dụ một prefix branch theo ngày. Một run ID. Một expected artifact ID. Một key theo date + workflow.

Khi đó, “đã có thứ khác” không thể vô tình thay thế “đã hoàn thành đúng phần việc của workflow này”.

Đây cũng là cách tránh một lỗi phổ biến trong hệ thống nhiều automation: các luồng khác nhau cùng tạo artifact giống nhau rồi vô tình che lỗi của nhau.

Fallback nên giảm tham vọng, không giảm cadence

Một pipeline content còn có bài toán khác: không phải ngày nào cũng có tin mới đủ mạnh.

Nếu workflow đặt mục tiêu Bắt Nhịp, có thể có ngày không có nguồn chính thức mới và đủ liên quan.

Phản ứng không nên là bịa tin hoặc cố kéo một thay đổi nhỏ thành một bài lớn.

Nhưng cũng không nhất thiết phải bỏ cả daily slot.

Có thể giảm tham vọng theo thứ tự:

Bắt Nhịp → Knowledge → Tản Mạn.

Không có tin đủ mạnh thì viết một Knowledge bền hơn.

Không có material factual đủ tốt thì viết một Tản Mạn dựa trên một nguyên tắc vận hành thực sự đáng suy nghĩ.

Fallback tốt không phải là “bất chấp chất lượng để đủ số”.

Nó là thiết kế sẵn nhiều loại output phù hợp với mức bằng chứng hiện có, để workflow vẫn giữ nhịp mà không cần bịa.

Điều này làm hệ thống bền hơn rất nhiều so với việc chỉ có một con đường duy nhất.

Một automation tốt nên tự chứng minh mình hoàn tất

Tôi nghĩ đây là nguyên tắc quan trọng nhất.

Một hệ thống tự động càng ít cần con người kiểm tra thủ công mỗi ngày thì càng tốt. Nhưng muốn đạt điều đó, hệ thống phải tự để lại đủ bằng chứng để chính nó hoặc một watchdog độc lập có thể trả lời:

  • Hôm nay task có chạy không?
  • Nó đã tạo gì?
  • Artifact nằm ở đâu?
  • Ngày trong artifact có đúng không?
  • Trạng thái có đúng không?
  • Output cuối đã tồn tại ở hệ thống đích chưa?
  • Nếu dừng giữa chừng, có thể tiếp tục từ bước nào?
  • Retry có tạo duplicate không?

Khi những câu hỏi này có câu trả lời máy đọc được, automation bắt đầu trở thành một hệ thống vận hành chứ không chỉ là một chuỗi thao tác.

Đây cũng là lúc monitoring thay đổi vai trò.

Monitoring không còn chỉ là “có lỗi hay không”.

Nó trở thành bằng chứng rằng công việc đã đi hết quãng đường cần thiết.

Điều tôi muốn giữ lại

Khi một lịch tự động bị lỗi, phản xạ đầu tiên thường là sửa cron, bật lại task hoặc chạy lại workflow.

Những việc đó có thể cần.

Nhưng nếu chỉ sửa ở tầng trigger, cùng một loại lỗi vẫn có thể quay lại ở một bước khác.

Điều đáng làm hơn là định nghĩa lại thế nào mới được gọi là hoàn tất.

Một scheduled task không hoàn tất vì nó đã được scheduler gọi.

Một agent không hoàn tất vì nó nói “done”.

Một API không hoàn tất vì trả mã thành công.

Một workflow không hoàn tất vì biểu đồ các node đã chuyển sang màu xanh.

Nó hoàn tất khi đầu ra mà người dùng thực sự cần tồn tại, đúng trạng thái, đúng phạm vi và đã được xác nhận bằng bằng chứng độc lập.

Tự động hóa tốt không chỉ giúp con người bớt phải làm.

Nó còn phải giúp con người bớt phải đoán xem hệ thống đã làm xong thật chưa.