Workflow vừa tiếp nhận một yêu cầu, tạo xong task trên hệ thống quản lý công việc rồi chuyển sang gửi thông báo cho đội ngũ. Action gửi thông báo trả về timeout. Trên màn hình quản trị, lượt chạy (execution) chuyển sang màu đỏ báo lỗi.
Nút chạy lại nằm ngay trước mắt, nhưng nếu bấm ngay vào lúc này, bạn rất dễ tạo thêm một task thứ hai giống hệt task trước. Trạng thái timeout chỉ phản ánh việc workflow không nhận được phản hồi trong thời gian quy định; hệ thống đích có thể đã tạo task thành công trước khi kết nối mạng bị gián đoạn.
Khôi phục một workflow gặp sự cố không bao giờ bắt đầu bằng việc bấm retry vội vã. Bạn cần xác định rõ thao tác nào đã hoàn tất thật sự, thao tác nào chắc chắn chưa chạy và thao tác nào đang ở trạng thái chưa rõ ràng. Chỉ khi có bằng chứng cụ thể từ hệ thống đích, bạn mới nên quyết định chạy lại bước lỗi, tiếp tục từ điểm ngắt hay xử lý nốt phần việc còn lại bằng tay.
Vòng đời xử lý lỗi có kiểm soát: Khử trùng lặp bằng Idempotency, Thử lại thông minh bằng Exponential Backoff và cách ly an toàn qua Dead-Letter Queue.
Ngăn lỗi tiếp tục lan rộng
Nếu các lượt chạy tương tự vẫn liên tục phát sinh và báo lỗi, việc đầu tiên cần làm là khoanh vùng để sự cố không trầm trọng thêm. Bạn có thể tạm dừng trigger tiếp nhận, giới hạn luồng dữ liệu đầu vào hoặc tạm chuyển các bước ghi dữ liệu sang chế độ chỉ ghi log. Trước khi tắt một workflow quan trọng, hãy kiểm tra kỹ xem các yêu cầu gửi đến trong lúc tắt sẽ được lưu vào hàng đợi hay bị mất hoàn toàn.
Nếu workflow nhận sự kiện qua webhook hay hàng đợi tin nhắn, bạn cần biết hệ thống gửi có cơ chế lưu đệm hay không. Một số trigger sẽ bỏ qua mọi sự kiện phát sinh trong lúc luồng bị tắt. Trong trường hợp đó, bạn phải ghi lại mốc thời gian bắt đầu dừng để sau này truy vấn và xử lý bù dữ liệu.
Khi sự cố làm chậm trễ tiến độ công việc chung, hãy thông báo ngắn gọn cho những người đang đợi kết quả. Nội dung thông báo chỉ cần nêu rõ phạm vi ảnh hưởng, trạng thái đang xử lý và cách liên hệ trong trường hợp khẩn cấp, thay vì gửi đi một đoạn mã lỗi dài khó hiểu.
Mở đúng execution trước khi sửa workflow
Hãy ghi lại execution ID, mã định danh yêu cầu đầu vào (input reference), thời điểm bắt đầu và bước cuối cùng đang hiển thị. Với ví dụ tạo task ở trên, input reference có thể là request_id từ biểu mẫu gửi lên, còn kết quả cần đối chiếu là ID của task trên hệ thống công việc.
Sau đó, bạn đối chiếu từng bước trong luồng theo ba trạng thái:
- Chưa thực hiện: có bằng chứng rõ ràng là request chưa được gửi đi hoặc action chưa từng được gọi.
- Đã thực hiện: tìm thấy task, tin nhắn hoặc bản ghi tương ứng đã nằm trong hệ thống đích.
- Chưa xác định: request đã rời khỏi workflow nhưng chưa nhận được phản hồi xác nhận tin cậy.
Trạng thái chưa xác định bắt buộc phải giữ nguyên cho đến khi bạn kiểm tra trực tiếp trên hệ thống đích. Nếu bạn vội vàng xem bước đó là thất bại chỉ vì thấy node báo đỏ, thao tác chạy lại rất dễ tạo ra dữ liệu trùng lặp.
Log của workflow chỉ là một nguồn tham khảo, không phải căn cứ duy nhất. Bạn hãy mở trực tiếp hệ thống đích, tìm kiếm theo mã giao dịch, request ID hoặc các thông tin đi kèm bản ghi. Nếu một action như gửi email không hỗ trợ tra cứu lịch sử gửi, phương án khôi phục cần được tính toán cẩn thận hơn vì bạn không thể chứng minh chắc chắn email đó đã ra khỏi hệ thống hay chưa.
Phân loại lỗi trước khi chọn retry
Mỗi nhóm lỗi đòi hỏi một cách ứng xử riêng. Nếu dữ liệu đầu vào sai định dạng, việc retry thêm nhiều lần cũng không làm nó hợp lệ hơn. Tương tự, việc làm mới token liên tục cũng vô ích nếu tài khoản kết nối đang bị chặn quyền truy cập.
| Loại lỗi | Dấu hiệu thường gặp | Hướng xử lý |
|---|---|---|
| Dữ liệu đầu vào hoặc validation | Thiếu trường bắt buộc, sai kiểu dữ liệu | Sửa dữ liệu tại nguồn hoặc nhờ người nhập kiểm tra lại |
| Xác thực hoặc phân quyền | Token hết hạn, mã lỗi 401 hoặc 403 | Cập nhật lại credential hoặc cấp đúng quyền truy cập |
| Cấu hình hoặc tài nguyên | Endpoint đổi đường dẫn, ID đối tượng không tồn tại | Cập nhật lại cấu hình hoặc đường dẫn kết nối trong workflow |
| Chạm ngưỡng giới hạn (rate limit) | Mã lỗi 429, thông báo vượt quota tạm thời | Đọc header Retry-After, tạm dừng và thử lại có kiểm soát |
| Gián đoạn mạng hoặc dịch vụ tạm thời | Connection reset, lỗi 502, 503 hoặc 504 | Thực hiện retry có giãn cách nếu thao tác an toàn khi lặp lại |
| Hết thời gian chờ (timeout) | Không nhận được phản hồi trong thời hạn | Kiểm tra hệ thống đích trước khi quyết định gửi lại |
| Từ chối theo quy tắc nghiệp vụ | Trạng thái bản ghi không cho phép cập nhật | Ghi nhận lý do, dừng luồng hoặc chuyển cho người phụ trách |
Mã lỗi HTTP chỉ là điểm khởi đầu. Nhiều hệ thống có quy ước riêng và trả thông tin chi tiết trong phần thân phản hồi (body). Khi gặp lỗi, bạn nên đọc tài liệu của API hoặc connector đang dùng thay vì áp dụng một quy tắc retry cứng nhắc cho mọi tình huống.
Timeout không đồng nghĩa action chưa chạy
Khi workflow gửi một yêu cầu qua API, có rất nhiều việc diễn ra giữa lúc phát request và lúc nhận kết quả. Máy chủ phía đích có thể đã tạo xong dữ liệu nhưng đường truyền mạng bị ngắt ngay lúc gửi phản hồi về. Workflow phía bạn chỉ nhận được thông báo timeout, trong khi dữ liệu thực tế đã nằm trên hệ thống đích.
Đây là lý do những bước ghi hoặc sửa dữ liệu cần có cơ chế gửi kèm mã định danh thao tác (idempotency key hoặc operation key). Khi workflow thử lại cùng một yêu cầu, nó sẽ gửi nguyên vẹn key này kèm theo. Nếu dịch vụ đích hỗ trợ tính năng idempotency, máy chủ sẽ nhận ra đây là yêu cầu đã được xử lý trước đó và trả về kết quả cũ thay vì tạo thêm một bản ghi mới.
Cổng thanh toán Stripe là một ví dụ điển hình: họ lưu kết quả của lần gọi đầu tiên gắn với idempotency key để khi nhận lại key trùng lặp, hệ thống trả về nguyên vẹn kết quả trước đó. Tuy nhiên, đây là thiết kế riêng của từng dịch vụ chứ không phải mặc định của mọi API. Bạn cần kiểm tra xem endpoint đang kết nối có hỗ trợ cơ chế này không, key được lưu trong bao lâu và hệ thống sẽ phản ứng ra sao nếu bạn gửi cùng key nhưng thay đổi tham số.
Tuyệt đối không tái sử dụng key cũ cho một thao tác nghiệp vụ mới. Hai yêu cầu khác nhau phải mang hai key riêng biệt, ngay cả khi các trường dữ liệu bên trong hoàn toàn giống nhau.
Khi nào retry có ích?
Cơ chế retry tự động chỉ phù hợp với các lỗi có khả năng tự hết sau một khoảng thời gian ngắn: mạng chập chờn, dịch vụ phía bạn gọi tạm thời bận hoặc chạm ngưỡng giới hạn tần suất gửi yêu cầu. Điều kiện tiên quyết là dữ liệu gửi đi phải hoàn toàn hợp lệ và thao tác đó phải an toàn khi gọi lặp lại.
Khi retry, bạn không nên gửi lại yêu cầu dồn dập. Nếu nhiều lượt chạy cùng thử lại tại một thời điểm, chính lượng request này sẽ tạo thêm tải và làm sập luôn dịch vụ đang gặp sự cố. Thuật toán lũy tiến thời gian chờ (exponential backoff) giúp tăng dần khoảng nghỉ giữa các lần thử. Bạn cũng nên kết hợp thêm jitter (một khoảng lệch ngẫu nhiên) để các lượt chạy không đồng loạt đập vào máy chủ cùng một giây.
Số lần thử, khoảng nghỉ và thời gian timeout cần được cân đối theo tính chất công việc. Một luồng đồng bộ dữ liệu chạy ngầm có thể chờ vài chục phút trước khi thử lại, nhưng một luồng xử lý giao diện có người dùng đang chờ thì cần phản hồi nhanh hơn. Nếu bên dịch vụ trả về header quy định thời gian chờ, workflow cần tuân thủ đúng chỉ dẫn đó.
Mỗi cơ chế retry đều phải có giới hạn số lần thử và điểm dừng an toàn. Khi đã chạm ngưỡng tối đa mà vẫn thất bại, workflow cần dừng lại và phát tín hiệu cảnh báo để người vận hành vào kiểm tra. Bạn có thể tham khảo cách thiết kế cảnh báo để người nhận biết phải làm gì để thông báo gửi về có đủ thông tin xử lý ngay thay vì chỉ báo lỗi chung chung.
Retry action lỗi hay chạy lại toàn workflow?
Giả sử quy trình của bạn gồm bốn bước tuần tự:
- Tiếp nhận và kiểm tra tính hợp lệ của yêu cầu.
- Tạo task trên phần mềm quản lý công việc.
- Cập nhật task ID ngược lại yêu cầu gốc.
- Gửi email thông báo cho các bên liên quan.
Nếu bước 2 và bước 3 đã chạy xong nhưng bước 4 bị lỗi mạng khi gửi email, chỉ có bước thông báo là chưa hoàn tất. Nếu bạn bấm chạy lại toàn bộ workflow từ đầu, bước 2 sẽ phải tự biết cách kiểm tra xem task đã tồn tại hay chưa để không tạo thêm bản ghi mới. Nếu workflow chưa được thiết kế để xử lý việc này, việc an toàn hơn là chỉ chạy lại riêng bước 4 hoặc gửi email bằng tay.
Nhiều nền tảng tự động hóa hiện nay cho phép chạy lại riêng những job hoặc nhánh bị hỏng. Trong GitHub Actions, bạn có thể chọn chạy lại toàn bộ quy trình, chạy lại các job thất bại hoặc chỉ chạy một job cụ thể. Tuy nhiên, việc công cụ có sẵn tính năng rerun không đồng nghĩa với việc chạy lại sẽ an toàn về mặt dữ liệu. Bạn vẫn phải nắm rõ thao tác chạy lại đó sẽ sử dụng dữ liệu đầu vào nào và có tạo ra tác động ngoài ý muốn hay không.
Nếu bạn vừa sửa lại logic của workflow sau khi phát hiện lỗi, hãy ghi nhớ phiên bản đang áp dụng. Việc cho một lượt chạy cũ chạy lại theo định nghĩa workflow mới có thể khiến dữ liệu đi vào một nhánh xử lý hoàn toàn khác.
Khôi phục thủ công mà vẫn giữ dấu vết
Xử lý thủ công không có nghĩa là bạn âm thầm vào từng phần mềm sửa dữ liệu cho xong chuyện rồi bỏ qua. Để quy trình sau này không bị lệch số liệu, bạn nên tạo một bản ghi khôi phục (recovery record) gắn liền với lượt chạy ban đầu:
- Mã định danh của lượt chạy và yêu cầu đầu vào liên quan.
- Kết quả thực tế đã được xác nhận ở từng hệ thống bên ngoài.
- Nguyên nhân gốc của lỗi và phân loại lỗi.
- Các bước đã được chạy lại tự động, bỏ qua hoặc làm bằng tay.
- Mã ID của các bản ghi được tạo bổ sung trong quá trình xử lý.
- Thời điểm hoàn tất và người chịu trách nhiệm thao tác.
Nếu bạn phải tạo task bằng tay trên phần mềm công việc, hãy cập nhật lại task ID đó vào yêu cầu gốc đúng như những gì workflow dự kiến làm. Nếu phải gửi lại thông báo cho người dùng, nội dung nên ghi rõ đây là thông báo cập nhật cho sự cố vừa qua để người nhận không tưởng nhầm là có một yêu cầu mới phát sinh.
Bạn cũng cần phân biệt rõ giữa thao tác bù (compensation) và việc khôi phục hoàn toàn (rollback). Xóa một task vừa tạo nhầm không làm biến mất toàn bộ dấu vết: thông báo có thể đã gửi đi, nhật ký hệ thống đã ghi nhận và các bộ phận khác có thể đã đọc được thông tin đó. Hãy gọi đúng đó là thao tác bù và kiểm tra kỹ các hệ thống liên quan, thay vì chủ quan cho rằng mọi thứ đã trở lại nguyên trạng ban đầu.
Xác nhận workflow đã phục hồi
Một lượt chạy chuyển sang màu xanh trên màn hình chưa phải là căn cứ duy nhất để kết luận sự cố đã xong. Bạn cần đối chiếu lại kết quả thực tế trên nghiệp vụ:
- Mỗi yêu cầu đầu vào chỉ tạo ra đúng số lượng kết quả tương ứng.
- Không có task, email hoặc bản ghi nào bị tạo trùng lặp.
- Toàn bộ dữ liệu phát sinh trong thời gian workflow tạm dừng đã được rà soát và xử lý bù.
- Danh sách hàng đợi lỗi không còn mục nào bị bỏ sót.
- Các chỉ số giám sát và thông báo cảnh báo đã trở về trạng thái bình thường.
Khi mở lại trigger tiếp nhận, bạn nên mở theo từng đợt nhỏ nếu hệ thống cho phép và theo dõi chặt chẽ vài lượt chạy đầu tiên. Nếu lượng yêu cầu tồn đọng (backlog) quá lớn, hãy xả dữ liệu từ từ theo năng lực xử lý của hệ thống đích; việc xả ồ ạt cùng lúc rất dễ làm nghẽn API và kích hoạt một vòng lặp sự cố mới.
Khi nào cần phân tích nguyên nhân gốc?
Một lỗi cấu hình nhỏ được phát hiện và sửa ngay trong quá trình chạy thử nghiệm chỉ cần ghi chú ngắn gọn. Tuy nhiên, với những lỗi lặp lại nhiều lần, gây thất thoát hoặc trùng lặp dữ liệu, gửi nhầm thông tin ra ngoài hoặc làm gián đoạn các khâu công việc tiếp theo, bạn cần ngồi lại để tìm nguyên nhân gốc.
Buổi phân tích nên tập trung vào những lỗ hổng trong thiết kế đã để cho sự cố xảy ra: thiếu cơ chế idempotency, không có khóa định danh thao tác, cấu hình timeout chưa hợp lý hoặc luồng xử lý thủ công chưa rõ ràng. Bạn có thể tham khảo mẫu ghi nhận và cách đặt câu hỏi trong bài Postmortem sự cố nhỏ nên ghi những gì?.
Checklist xử lý lỗi và khôi phục workflow
- ☐ Đã tạm dừng hoặc giới hạn nguồn tiếp nhận yêu cầu để khoanh vùng sự cố.
- ☐ Đã ghi lại execution ID, mã định danh yêu cầu và mốc thời gian xảy ra lỗi.
- ☐ Đã kiểm tra trực tiếp trên hệ thống đích thay vì chỉ nhìn màu sắc hiển thị của node.
- ☐ Đã phân loại từng bước theo ba trạng thái: chưa thực hiện, đã thực hiện hoặc chưa xác định.
- ☐ Đã xác định đúng nhóm lỗi trước khi quyết định có retry hay không.
- ☐ Đã kiểm tra tài liệu API để đảm bảo thao tác an toàn khi gọi lặp lại.
- ☐ Thao tác retry sử dụng đúng idempotency key hoặc operation key của yêu cầu gốc.
- ☐ Cơ chế retry có cấu hình timeout, khoảng nghỉ tăng dần và giới hạn số lần thử.
- ☐ Có ghi chép lại các bước đã xử lý tự động và các bước làm thủ công.
- ☐ Đã đối chiếu kết quả thực tế trên các hệ thống để đảm bảo không sinh dữ liệu trùng.
- ☐ Trigger được mở lại có kiểm soát và lượng yêu cầu tồn đọng được xử lý an toàn.
- ☐ Sự cố gây ảnh hưởng nghiêm trọng đã được phân tích nguyên nhân gốc để phòng ngừa tái diễn.
Một quy trình khôi phục chỉ được xem là hoàn tất khi mọi dữ liệu đầu vào đều có kết quả đầu ra tương ứng, các bước chạy lại không sinh rác và người vận hành hiểu rõ vì sao lượt chạy trước đó thất bại. Để thiết lập các cơ chế an toàn này ngay từ đầu, bạn nên tham khảo cấu trúc tổng thể trong bài Một workflow automation gồm những thành phần nào? và cân nhắc các giới hạn vận hành tại bài Khi nào không nên tự động hóa một quy trình?. Nếu bạn đang trong giai đoạn xây dựng quy trình đầu tiên, hãy bắt đầu từ lộ trình tại bài Tự động hóa công việc nên bắt đầu từ quy trình nào?.



