Chào bạn,
Ở bài học trước, chúng ta đã thành công trong việc kết hợp Parallel và Exclusive Gateway để xây dựng một quy trình vận đơn phức tạp hơn, có khả năng xử lý các công việc song song và ra quyết định. Bạn đã cấu hình một điều kiện rẽ nhánh bằng Expression Language: #{shippingMethod == 'express'}. Quy trình đã hoạt động hoàn hảo khi mọi thứ được thiết lập đúng.
Nhưng trong thế giới thực, lỗi là điều không thể tránh khỏi. Điều gì sẽ xảy ra nếu bạn gõ nhầm tên biến thành shippinMethod? Hoặc nếu biến đó chưa được tạo ra khi quy trình đi đến gateway? Những lỗi logic như vậy là một trong những nguyên nhân phổ biến nhất gây ra sự cố trong các quy trình tự động hóa.
Bài học hôm nay sẽ trang bị cho bạn kỹ năng thiết yếu để giải quyết vấn đề này. Mục tiêu của chúng ta là debug và xử lý các lỗi logic trong điều kiện của gateway. Bạn sẽ học cách Camunda Engine báo cáo lỗi, cách sử dụng Camunda Cockpit như một công cụ gỡ lỗi mạnh mẽ để chẩn đoán và khắc phục sự cố, giúp quy trình của bạn trở nên ổn định và dễ bảo trì hơn.
1. Khi Logic Gặp Lỗi: "Incident" là gì?
Trong Camunda, khi một quy trình không thể tiếp tục thực thi do một lỗi kỹ thuật không lường trước, nó sẽ không bị "crash" và dừng lại hoàn toàn. Thay vào đó, engine sẽ tạm dừng luồng thực thi tại điểm xảy ra lỗi và tạo ra một "Incident" (sự cố).
Một Incident là một bản ghi về lỗi, chứa thông tin chi tiết về:
- Vị trí xảy ra lỗi: Task hoặc gateway nào đang gặp vấn đề.
- Nguyên nhân lỗi: Một thông báo lỗi (error message) và dấu vết ngăn xếp (stack trace).
- Ngữ cảnh của quy trình: Trạng thái của các biến tại thời điểm xảy ra lỗi.
Đối với gateway, các lỗi logic phổ biến gây ra Incident bao gồm:
- Sai tên biến: Ví dụ, biểu thức trông chờ biến
#{amount}nhưng bạn lại truyền vào biến tên làtotalAmount. - Biến không tồn tại: Biểu thức tham chiếu đến một biến chưa được khởi tạo.
- Lỗi kiểu dữ liệu hoặc giá trị
null: Cố gắng thực hiện một phép toán trên một biếnnullhoặc so sánh các kiểu dữ liệu không tương thích. - Lỗi cú pháp trong biểu thức: Biểu thức JUEL phức tạp bị viết sai.
Hiểu và xử lý Incident là một kỹ năng vận hành cốt lõi khi làm việc với Camunda.
2. Thực Hành: Cố Tình Tạo Ra Lỗi
Bây giờ, hãy quay lại dự án Spring Boot và quy trình vận đơn từ bài học trước. Chúng ta sẽ cố tình tạo ra một lỗi logic để xem Incident hoạt động như thế nào.
- Mở file BPMN của quy trình vận đơn trong Camunda Modeler.
- Chọn luồng đi ra (sequence flow) từ Exclusive Gateway đến Service Task "Chuẩn bị vận chuyển hỏa tốc".
- Trong Properties Panel, tìm đến biểu thức điều kiện.
- Thay đổi
#{shippingMethod == 'express'}thành#{shippinMethod == 'express'}(gõ thiếu chữ 'g'). - Lưu file BPMN và khởi động lại ứng dụng Spring Boot của bạn để deploy phiên bản mới.
- Sử dụng Postman, khởi tạo một thực thể quy trình (process instance) mới như bạn đã làm ở bài trước, với biến
orderId. - Mở Camunda Tasklist (
http://localhost:8080/camunda/app/tasklist/), bạn sẽ thấy hai task song song. - Claim và complete task "Xác định phương thức vận chuyển". Khi complete, hãy thêm biến
shippingMethod(gõ đúng) với giá trị làexpress.
Ngay sau khi bạn complete task, quy trình sẽ cố gắng đánh giá điều kiện tại Exclusive Gateway. Vì biểu thức #{shippinMethod == 'express'} tham chiếu đến một biến không tồn tại, Camunda Engine sẽ không biết phải đi theo nhánh nào và một Incident sẽ được tạo ra.
3. Sử Dụng Camunda Cockpit để Gỡ Lỗi
Camunda Cockpit là trung tâm điều khiển của bạn để giám sát và xử lý các quy trình đang chạy, đặc biệt là khi có sự cố.
-
Xác định Incident:
- Truy cập Camunda Cockpit (
http://localhost:8080/camunda/app/cockpit/). - Trên trang chủ, bạn sẽ thấy định nghĩa quy trình "Shipment Process" của mình có một huy hiệu màu đỏ, báo hiệu có một hoặc nhiều Incident đang hoạt động.
- Truy cập Camunda Cockpit (
-
Xem chi tiết Instance bị lỗi:
- Nhấp vào tên quy trình để xem danh sách các instance đang chạy. Bạn sẽ thấy instance vừa tạo đang ở trạng thái lỗi (có biểu tượng màu đỏ).
- Nhấp vào instance đó. Giao diện sẽ hiển thị sơ đồ quy trình, và bạn có thể thấy rõ "token" (mã thông báo thực thi) đang bị kẹt lại ngay tại Exclusive Gateway.
-
Phân tích nguyên nhân lỗi:
- Ở phía dưới màn hình, hãy chuyển sang tab Incidents.
- Bạn sẽ thấy một thông báo lỗi rất rõ ràng, tương tự như:
Cannot resolve identifier 'shippinMethod' in .... Đây chính là bằng chứng cho thấy vấn đề nằm ở đâu. - Bây giờ, hãy chuyển sang tab Variables. Bạn sẽ thấy biến
shippingMethodtồn tại với giá trịexpress. - Bằng cách so sánh thông báo lỗi (
Cannot resolve identifier 'shippinMethod') với danh sách biến (shippingMethod), bạn có thể kết luận ngay lập tức: biểu thức đã bị gõ sai tên biến.
Việc chẩn đoán này là bước đầu tiên và quan trọng nhất trong việc gỡ lỗi. Để hiểu sâu hơn về cách công cụ của Camunda giúp bạn giải quyết những sự cố này, hãy đọc bài viết sau. Mặc dù bài viết đề cập đến "Operate" (công cụ trong Camunda 8), các nguyên tắc và hành động về việc xem xét sự cố, thử lại và sửa đổi là hoàn toàn tương tự trong Cockpit của Camunda 7 mà chúng ta đang sử dụng.
Resolving Process Incidents and Exceptions with Operate
Bài viết 'Resolving Process Incidents and Exceptions with Operate' giải thích tại sao sự cố xảy ra và cách sử dụng các công cụ vận hành của Camunda để xác định và khắc phục chúng. Hãy tập trung vào các khái niệm cốt lõi.
Hãy đọc hai phần đầu tiên: 'Incidents happen' và 'How can Operate help?'. Chú ý cách bài viết mô tả các nguyên nhân phổ biến gây ra sự cố ('misspelled a variable name') và cách công cụ cho phép bạn 'see the process state of your instance as well as all current instance variables and values and any possible incidents'. Đây chính xác là những gì chúng ta vừa làm trong Cockpit.
4. Khắc Phục Incident
Sau khi đã chẩn đoán được lỗi, chúng ta có hai cách chính để khắc phục.
Cách 1: Sửa Lỗi Gốc (The Developer Fix)
Cách tiếp cận bền vững nhất là sửa lỗi ngay tại mô hình quy trình.
- Quay lại Camunda Modeler.
- Sửa lại biểu thức điều kiện từ
#{shippinMethod == 'express'}thành#{shippingMethod == 'express'}. - Lưu và redeploy lại quy trình.
Lưu ý quan trọng: Việc này chỉ áp dụng cho các process instance mới được tạo sau khi deploy. Instance đang bị kẹt trong Incident vẫn ở đó và cần được xử lý thủ công.
Cách 2: Sửa Nóng Instance đang chạy (The Operator Fix)
Đây là lúc sức mạnh vận hành của Cockpit phát huy tác dụng. Chúng ta có thể sửa instance đang bị lỗi mà không cần deploy lại code.
Resolving Process Incidents and Exceptions with Operate
Hãy tiếp tục với bài viết 'Resolving Process Incidents and Exceptions with Operate' để xem các tùy chọn khắc phục sự cố có sẵn.
Đọc các phần 'How to keep the process moving' và 'Modifying your process instance'. Bài viết mô tả hai hành động chính: Retry the task: Thử lại tác vụ sau khi đã khắc phục nguyên nhân. Modifying your process instance: Thay đổi trạng thái của quy trình, ví dụ như thêm/sửa biến hoặc di chuyển luồng thực thi.
Dựa trên những gì bạn vừa đọc, hãy thử áp dụng vào instance đang bị lỗi của chúng ta:
-
Thử lại (Retry): Trong tab Incidents, bạn sẽ thấy một nút "Retry" (biểu tượng mũi tên xoay tròn). Nếu bạn nhấn nút này ngay, nó sẽ thất bại một lần nữa, vì lỗi logic (sai tên biến) vẫn còn đó. "Retry" chỉ hiệu quả khi nguyên nhân gốc đã được giải quyết (ví dụ: một hệ thống bên ngoài bị sập đã hoạt động trở lại).
-
Sửa đổi biến và Thử lại: Đây là cách phù hợp cho trường hợp của chúng ta.
- Chuyển sang tab Variables.
- Nhấp vào nút Add Variable.
- Tạo một biến mới với tên là
shippinMethod(tên biến bị sai), kiểuString, và giá trị làexpress. - Bây giờ, quy trình đã có biến mà biểu thức đang tìm kiếm. Quay lại tab Incidents và nhấn nút Retry.
- Lần này, biểu thức sẽ được đánh giá thành công, và bạn sẽ thấy quy trình tiếp tục chạy qua gateway và đi đến tác vụ "Chuẩn bị vận chuyển hỏa tốc".
-
Di chuyển luồng thực thi (Modify): Đây là một công cụ rất mạnh mẽ. Thay vì sửa biến, bạn có thể ra lệnh cho engine bỏ qua gateway và đi thẳng đến một tác vụ cụ thể.
- Trong giao diện xem chi tiết instance, nhấp vào nút Modify (biểu tượng cờ lê).
- Bạn có thể hủy token đang bị kẹt tại gateway và thêm một token mới vào tác vụ "Chuẩn bị vận chuyển tiêu chuẩn" (nếu bạn muốn ghi đè logic và buộc quy trình đi theo nhánh này).
- Đây là một hành động "cấp cứu" mạnh mẽ nhưng cần cẩn trọng vì nó có thể bỏ qua các quy tắc nghiệp vụ quan trọng.
5. Phòng Bệnh Hơn Chữa Bệnh: Các Phương Pháp Tốt Nhất
Việc biết cách sửa lỗi là rất tốt, nhưng việc ngăn chặn chúng xảy ra ngay từ đầu còn tốt hơn.
- Luôn sử dụng Default Flow: Trên một Exclusive Gateway, hãy luôn chỉ định một trong các luồng đi ra làm Default Flow. Nếu không có điều kiện nào được đáp ứng (tất cả đều trả về
false), engine sẽ tự động đi theo luồng mặc định này thay vì tạo ra Incident. Đây là phương pháp phòng ngừa hiệu quả nhất. - Kiểm tra
nulltrong biểu thức: Khi làm việc với các biến đối tượng, hãy luôn kiểm tranulltrước khi gọi phương thức. Ví dụ:#{customer != null && customer.isActive()}. - Đơn giản hóa biểu thức: Nếu logic điều kiện quá phức tạp, hãy cân nhắc chuyển nó vào một Service Task (dùng
JavaDelegate) đặt ngay trước gateway. Service Task này sẽ thực thi logic phức tạp và đặt kết quả vào một biến đơn giản (ví dụ:decisionvới giá trị "A", "B", "C"). Gateway sau đó chỉ cần kiểm tra biến đơn giản này. - Tận dụng Camunda Modeler: Đôi khi, Modeler có thể cảnh báo bạn về các lỗi cấu hình ngay khi bạn đang thiết kế.

Tổng kết
Trong bài học này, bạn đã đi sâu vào một khía cạnh quan trọng của việc phát triển quy trình: xử lý lỗi.
Những điểm chính cần nhớ:
- Lỗi logic trong điều kiện của gateway sẽ tạo ra Incident, tạm dừng quy trình để chờ xử lý.
- Camunda Cockpit là công cụ không thể thiếu để chẩn đoán Incident bằng cách xem thông báo lỗi và trạng thái biến.
- Bạn có thể khắc phục Incident bằng cách sửa lỗi gốc và redeploy, hoặc sửa "nóng" instance đang chạy bằng cách thay đổi biến, thử lại (retry), hoặc di chuyển luồng thực thi (modify).
- Sử dụng Default Flow trên Exclusive Gateway là cách tốt nhất để ngăn chặn việc quy trình bị kẹt do không có điều kiện nào thỏa mãn.
Xem trước bài học tiếp theo
Chúng ta đã thấy rằng logic nghiệp vụ có thể được thực thi trong các JavaDelegate. Đến nay, các delegate của chúng ta còn khá đơn giản. Trong bài học tiếp theo, chúng ta sẽ bắt đầu module mới "Tích hợp Logic Nghiệp vụ với Java" và đi sâu hơn vào chủ đề này với bài học: "Implement interface JavaDelegate để thực thi logic trong một Service Task". Bạn sẽ học cách viết các lớp Java phức tạp hơn, tương tác với các biến quy trình một cách chi tiết, và thực sự biến các Service Task thành những đơn vị xử lý nghiệp vụ mạnh mẽ.