Chào bạn,
Ở bài học trước, chúng ta đã học cách dùng Intermediate Timer Catch Event để tạo ra một khoảng dừng trong luồng quy trình, chẳng hạn như chờ đợi một khoảng thời gian trước khi tiếp tục.
Trong bài học hôm nay, chúng ta sẽ khám phá một công cụ quản lý thời gian khác vô cùng hữu ích: Timer Boundary Event. Thay vì tạm dừng toàn bộ quy trình, sự kiện này cho phép chúng ta đặt một "đồng hồ đếm ngược" trên một tác vụ cụ thể. Nếu tác vụ đó không được hoàn thành trong thời gian quy định, một hành động thay thế sẽ được kích hoạt. Đây chính là cách chúng ta xử lý các kịch bản "timeout" (quá hạn) trong thực tế.
Mục tiêu của bài học này là: Sử dụng Timer Boundary Event để xử lý timeout cho một activity. Chúng ta sẽ học cách mô hình hóa, cấu hình và triển khai một quy trình có khả năng tự động leo thang (escalate) một công việc nếu nó bị trì hoãn.
1. Timer Boundary Event là gì?
Timer Boundary Event là một sự kiện được "gắn" vào đường biên của một activity (ví dụ như User Task hoặc Service Task). Khi luồng thực thi đi vào activity đó, bộ đếm thời gian của boundary event sẽ được kích hoạt.
Có hai loại Timer Boundary Event, và việc hiểu rõ sự khác biệt này là rất quan trọng:
-
Interrupting (Hủy bỏ):
- Ký hiệu: Vòng tròn nét liền.
- Hành vi: Nếu bộ đếm thời gian kết thúc trước khi activity hoàn thành, activity đó sẽ bị hủy bỏ ngay lập tức. Luồng thực thi sẽ được chuyển sang đường đi thay thế bắt nguồn từ timer event. Đây là cơ chế hoàn hảo để xử lý timeout và escalation.
-
Non-interrupting (Không hủy bỏ):
- Ký hiệu: Vòng tròn nét đứt.
- Hành vi: Nếu bộ đếm thời gian kết thúc, một luồng thực thi mới sẽ được tạo ra và đi theo đường đi thay thế. Activity gốc vẫn tiếp tục chạy bình thường. Cơ chế này phù hợp để gửi thông báo nhắc nhở định kỳ mà không làm gián đoạn công việc chính.
Để có một định nghĩa rõ ràng, hãy tham khảo tài liệu chính thức của Camunda.
Tài liệu này từ Camunda Docs giải thích một cách súc tích về Timer Boundary Events và cách chúng được sử dụng để mô hình hóa các kịch bản timeout.
Đọc toàn bộ mục 'Timer boundary events'. Hãy chú ý đến sự phân biệt giữa 'interrupting' (dùng để hủy bỏ xử lý) và 'non-interrupting' (dùng để gửi thông báo).
Hãy xem sơ đồ minh họa một kịch bản timeout kinh điển:

Trong bài học này, chúng ta sẽ tập trung vào Interrupting Timer Boundary Event để thực hiện đúng mục tiêu xử lý timeout.
2. Thực hành: Xử lý Timeout cho Tác vụ Phê duyệt
Chúng ta sẽ xây dựng một quy trình phê duyệt yêu cầu. Nếu người dùng được giao không hoàn thành tác vụ trong một khoảng thời gian nhất định, hệ thống sẽ tự động hủy tác vụ đó và gửi thông báo cho quản lý.
Kịch bản:
- Một yêu cầu phê duyệt được tạo ra (User Task: "Phê duyệt yêu cầu").
- Người dùng có 20 giây để hoàn thành tác vụ này.
- Nếu hoàn thành trong 20 giây: Quy trình kết thúc với trạng thái "Đã phê duyệt".
- Nếu không hoàn thành trong 20 giây: Tác vụ "Phê duyệt yêu cầu" sẽ bị hủy. Một tác vụ hệ thống (Service Task: "Thông báo quản lý về sự chậm trễ") sẽ được thực thi, và quy trình kết thúc với trạng thái "Đã leo thang".
Bước 1: Mô hình hóa quy trình
- Mở Camunda Modeler và tạo một quy trình mới.
- Thiết kế quy trình như sau:
- Bắt đầu với một Start Event.
- Thêm một User Task và đặt tên là
Phê duyệt yêu cầu. - Chọn User Task, click vào biểu tượng cờ lê (wrench) và chọn Append Timer Boundary Event. Camunda sẽ tạo một sự kiện với vòng tròn nét liền (interrupting).
- Từ User Task, kéo một Sequence Flow đến một End Event (đặt tên
Đã phê duyệt). Đây là luồng xử lý bình thường. - Từ Timer Boundary Event, kéo một Sequence Flow đến một Service Task (đặt tên
Thông báo quản lý về sự chậm trễ). - Từ Service Task này, kéo đến một End Event khác (đặt tên
Đã leo thang).
Quy trình của bạn sẽ trông tương tự như sơ đồ leo thang ở trên.
Bước 2: Cấu hình các phần tử
-
Cấu hình Timer Boundary Event:
- Chọn Timer Boundary Event trên mô hình.
- Trong Properties Panel:
- Tab
General: Đảm bảo checkboxCancel Activityđược chọn. Đây là yếu tố quyết định sự kiện có phải là interrupting hay không. - Tab
Timer:Timer Definition Type: ChọnDuration.Timer Definition: NhậpPT20S. (P: Period, T: Time, 20S: 20 Seconds).
- Tab
-
Cấu hình Service Task:
- Chọn Service Task
Thông báo quản lý về sự chậm trễ. - Trong Properties Panel, tab
General:Implementation: ChọnJava Class.Java Class: Nhậpcom.example.camunda.delegates.EscalationDelegate.
- Chọn Service Task
Bước 3: Viết mã Java Delegate
Trong project Spring Boot của bạn, tạo lớp EscalationDelegate sau. Lớp này chỉ đơn giản là in ra một thông báo để chúng ta biết luồng timeout đã được thực thi.
package com.example.camunda.delegates;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component("EscalationDelegate")
public class EscalationDelegate implements JavaDelegate {
private final Logger LOGGER = LoggerFactory.getLogger(EscalationDelegate.class);
@Override
public void execute(DelegateExecution execution) throws Exception {
String processInstanceId = execution.getProcessInstanceId();
LOGGER.warn("!!! TIMEOUT on Process Instance [{}]. Escalating to manager.", processInstanceId);
// Trong thực tế, bạn có thể gọi API để gửi email, tin nhắn, v.v.
}
}
Bước 4: Deploy và Kiểm thử
- Lưu file BPMN, deploy và khởi chạy ứng dụng Spring Boot.
- Mở Camunda Tasklist.
Kiểm thử kịch bản 1: Hoàn thành đúng hạn
- Start một process instance mới.
- Refresh Tasklist, bạn sẽ thấy tác vụ
Phê duyệt yêu cầu. - Ngay lập tức (trong vòng 20 giây), claim và complete tác vụ.
- Mở Cockpit, tìm process instance vừa chạy. Bạn sẽ thấy nó đã đi theo luồng bình thường và kết thúc ở End Event
Đã phê duyệt.
Kiểm thử kịch bản 2: Xử lý quá hạn (Timeout)
- Start một process instance mới.
- Refresh Tasklist, bạn sẽ thấy tác vụ
Phê duyệt yêu cầu. - Không làm gì cả. Đợi hơn 20 giây.
- Quan sát:
- Trong Tasklist, tác vụ
Phê duyệt yêu cầusẽ biến mất vì nó đã bị hủy. - Trong Console của ứng dụng, bạn sẽ thấy log:
!!! TIMEOUT... Escalating to manager.. - Trong Cockpit, tìm process instance đó. Bạn sẽ thấy luồng thực thi đã đi qua Timer Boundary Event, thực thi Service Task và kết thúc ở End Event
Đã leo thang.
- Trong Tasklist, tác vụ
3. Non-interrupting Timer Boundary Event
Để hoàn thiện kiến thức, hãy xem cách Non-interrupting Timer Boundary Event hoạt động. Nó không hủy tác vụ gốc mà tạo ra một hành động song song, rất hữu ích cho việc gửi lời nhắc.
Hãy xem video sau để thấy cách nó được mô hình hóa và hoạt động trong thực tế.
Camunda Platform 7 Tutorial: Running Timer Events, Catching BPMN Error Events in Spring Boot Project
Video này từ Camunda trình bày một ví dụ về Non-interrupting Timer Boundary Event. Nó cho thấy cách một tác vụ phụ (gửi thư) được tạo ra định kỳ mà không làm gián đoạn tác vụ chính.
Hãy xem từ 00:00 đến 05:25. Chú ý đến các điểm chính: sự kiện timer có vòng tròn nét đứt, cấu hình Cycle để lặp lại, và cách một token mới được tạo ra trên luồng phụ trong khi token chính vẫn ở lại tác vụ gốc.
Để chuyển một Timer Boundary Event từ interrupting sang non-interrupting trong Modeler, bạn chỉ cần bỏ chọn checkbox Cancel Activity trong Properties Panel. Giao diện sẽ tự động cập nhật đường viền của sự kiện thành nét đứt.
Tổng kết
Trong bài học này, chúng ta đã nắm vững một trong những công cụ mạnh mẽ nhất để quản lý thời gian trong BPMN.
Những điểm chính cần ghi nhớ:
- Timer Boundary Event được gắn vào một activity để xử lý các sự kiện liên quan đến thời gian cho riêng activity đó.
- Interrupting Event (nét liền,
Cancel Activity= true) hủy bỏ activity và chuyển hướng luồng đi. Đây là cách tiêu chuẩn để implement timeout và escalation. - Non-interrupting Event (nét đứt,
Cancel Activity= false) tạo ra một luồng song song mà không ảnh hưởng đến activity gốc, phù hợp cho việc nhắc nhở (reminders). - Cấu hình thời gian (ví dụ:
PT20S) được thực hiện trong tabTimercủa Properties Panel bằng định dạng ISO 8601.
Xem trước bài học tiếp theo
Chúng ta đã khám phá các loại Timer Event khác nhau. Bây giờ, hãy chuyển sang một loại sự kiện quan trọng khác dùng để giao tiếp: Message Events. Trong bài học tiếp theo, chúng ta sẽ tìm hiểu cách các quy trình khác nhau có thể "nói chuyện" và phối hợp với nhau bằng cách gửi và nhận tin nhắn, một khái niệm cốt lõi trong kiến trúc microservices và các hệ thống phức tạp.