8.0 KiB
PART 2 — biến thể batch-job
Dùng khi
PRODUCT = batch-job— job chạy theo lịch, không giao diện: đối soát đêm, sinh báo cáo định kỳ, dọn dữ liệu, gửi thông báo hàng loạt. Cắm khối này vào chỗ PART 2 của../srs.md.Tiêu chí G3 riêng của biến thể này: mỗi job có lịch + cửa sổ + phụ thuộc · quy tắc xử lý từng bản ghi đầy đủ · đã trả lời xong idempotency và thất bại giữa chừng · có kế hoạch cảnh báo và người trực.
Phân biệt với data-pipeline: pipeline có sản phẩm là dữ liệu để phân tích (cần
data contract, lineage, đối soát nguồn–đích); batch-job có sản phẩm là việc được làm xong
(cần idempotency, checkpoint, cảnh báo). Job vừa di chuyển dữ liệu lớn vừa làm việc nghiệp
vụ ⇒ nạp cả hai biến thể.
2.1 Danh sách job
| ID | Job | Làm gì | Lịch | Cửa sổ cho phép | Phụ thuộc job nào | Khối lượng/lần |
|---|---|---|---|---|---|---|
| JOB-01 | Hằng ngày 01:00 | 01:00–05:00 | JOB-00 xong | ~… bản ghi |
Cột Cửa sổ cho phép — job phải xong trước mấy giờ, và vì sao (nghiệp vụ nào bắt đầu
lúc đó). Không có cột này thì không ai biết chạy chậm bao lâu là sự cố.
2.2 Sơ đồ phụ thuộc
flowchart LR
J00["JOB-00 · 02:00 Nạp dữ liệu"]
J01["JOB-01 · 02:30 Đối soát"]
J02["JOB-02 · 03:00 Gửi báo cáo"]
STOP(["⛔ Dừng chuỗi · cảnh báo trực đêm"])
J00 -->|xong| J01
J01 -->|xong| J02
J00 -->|thất bại| STOP
J01 -->|thất bại| STOP
Nhãn node mang giờ chạy; ID khớp cột ID bảng §2.1.
🔴 Vẽ cả cạnh thất bại. Sơ đồ chỉ có đường "xong" bỏ sót đúng câu hỏi quan trọng nhất: job trước hỏng thì job sau chạy hay dừng.
Bảng đi kèm (quy tắc W13):
| Job | Phụ thuộc | Job trước thất bại ⇒ | Chạy với dữ liệu cũ có nguy hiểm không | Ai được báo |
|---|---|---|---|---|
| JOB-01 | JOB-00 | Dừng, không chạy | 🔴 Có — đối soát trên dữ liệu thiếu ra kết quả sai | Trực đêm |
| JOB-02 | JOB-01 | Dừng, không gửi báo cáo | 🔴 Có — gửi báo cáo sai còn tệ hơn không gửi | Trực đêm + kế toán |
Cột áp chót là cột quyết định: dữ liệu cũ vô hại ⇒ cho chạy tiếp; nguy hiểm ⇒ phải dừng.
Không trả lời được ⇒ OQ, đừng mặc định cho chạy.
2.3 JOB-01 — <Tên job>
2.3.1 Định danh
| Kích hoạt bởi | Lịch / Sự kiện / Gọi tay |
| Đầu vào | (bảng, file, hàng đợi — và phạm vi: ngày nào, trạng thái nào) |
| Đầu ra | (bản ghi được cập nhật, file sinh ra, thông báo gửi đi) |
| Thời gian chạy dự kiến | ~… phút với khối lượng bình thường |
| Chạy bao lâu thì coi là treo | |
| Có thể chạy đồng thời nhiều bản không | 🔴 Không ⇒ cơ chế khoá là gì |
2.3.2 Phạm vi xử lý
| Chọn bản ghi nào để xử lý | (điều kiện chính xác) |
| Bản ghi đã xử lý rồi nhận biết bằng gì | 🔴 (cột trạng thái? bảng log? mốc thời gian?) |
| Thứ tự xử lý có quan trọng không | |
| Giới hạn số bản ghi mỗi lần chạy | (và phần còn lại xử lý khi nào) |
2.3.3 Quy tắc xử lý từng bản ghi
Đây là phần thay thế cho "bảng field" của biến thể screen — phải cụ thể ngang vậy.
| # | Điều kiện | Hành động | Kết quả ghi vào đâu | BR |
|---|---|---|---|---|
| 1 | BR-0nn |
Bản ghi lỗi giữa chừng:
| Tình huống | Xử lý | Ghi log gì |
|---|---|---|
| Dữ liệu bản ghi không hợp lệ | Bỏ qua và tiếp tục / Dừng cả job | |
| Gọi hệ thống ngoài thất bại | Retry mấy lần? Rồi sao? |
🔴 "Bỏ qua và tiếp tục" phải kèm ngưỡng. Bỏ qua 3 bản ghi là bình thường; bỏ qua 30% số bản ghi là sự cố nhưng job vẫn báo "thành công" — đó là chế độ hỏng im lặng.
| Ngưỡng tỷ lệ lỗi để job tự đánh dấu thất bại | > …% |
2.3.4 Idempotency — chạy lại
🔴 Câu hỏi bắt buộc, không được để trống:
| Câu hỏi | Trả lời |
|---|---|
| Chạy lại cùng một ngày hai lần ⇒ kết quả có giống lần đầu không? | ✅/❌ |
| Nếu ❌: hậu quả cụ thể là gì | (gửi email hai lần? cộng tiền hai lần?) |
| Nếu ❌: quy trình dọn trước khi chạy lại | |
| Ai được phép chạy lại | |
| Chạy lại có cần khoảng thời gian cụ thể không |
Job gửi thông báo, ghi bút toán, gọi API bên ngoài mà không idempotent là rủi ro nghiêm
trọng — nêu rõ trong RISK chứ không chỉ ghi ở đây.
2.3.5 Thất bại giữa chừng
| Có checkpoint không | ✅/❌ — lưu ở đâu, mức nào (mỗi bản ghi? mỗi lô?) |
| Chạy lại tiếp tục từ checkpoint hay từ đầu | |
| Có rollback không | Toàn bộ / Không có / Từng lô |
| Trạng thái dở dang có làm hỏng nghiệp vụ khác không | 🔴 (job sau đọc dữ liệu chưa xong) |
| Cách nhận biết job đang chạy dở vs. đã xong |
2.3.6 Chạy tay
| Ai được chạy tay | |
| Tham số truyền được | (ngày nào, phạm vi nào) |
| Có cần phê duyệt không | (bắt buộc nếu RIGOR = strict) |
| Chạy tay có ghi vết khác chạy tự động không |
2.4 Trạng thái tương đương "màn hình rỗng"
| Tình huống | Job làm gì | Coi là thành công? |
|---|---|---|
| Không có bản ghi nào thoả điều kiện | Kết thúc, ghi log "0 bản ghi" | ✅ Có — không phải lỗi |
| Đầu vào chưa sẵn sàng (job trước chưa xong) | Chờ / Bỏ qua lần này / Báo lỗi | |
| Chạy đúng lịch nhưng hôm đó nghỉ lễ |
🔴 Phân biệt "không có gì để làm" với "không lấy được dữ liệu". Cả hai đều ra 0 bản ghi nhưng ý nghĩa ngược nhau, và gộp chúng làm sự cố bị bỏ qua nhiều ngày.
2.5 Cảnh báo và vận hành
| Sự kiện | Mức | Báo cho ai | Qua kênh nào | Trong bao lâu |
|---|---|---|---|---|
| Job thất bại | 🔴 | Ngay | ||
| Job chạy quá cửa sổ cho phép | 🔴 | Ngay | ||
| Tỷ lệ bản ghi lỗi vượt ngưỡng | 🟠 | Ngay | ||
| Job không chạy (lịch không kích hoạt) | 🔴 | Sau … phút quá giờ |
🔴 Dòng cuối là dòng hay bị quên nhất. Job thất bại thì có cảnh báo; job không chạy thì im lặng hoàn toàn — không có gì để báo lỗi. Phải có cơ chế phát hiện "đến giờ mà chưa thấy job nào bắt đầu".
| Ai trực ban đêm | |
| Sổ tay xử lý sự cố ở đâu | (đây là MANUAL của GĐ5 với loại sản phẩm này) |
| Hỏng bao lâu thì phải báo người dùng nghiệp vụ |
2.6 Nghiệm thu — thay cho UAT thông thường
| # | Cách kiểm | Tiêu chí đi tiếp |
|---|---|---|
| 1 | Chạy trên dữ liệu sao chép từ môi trường thật | Kết quả khớp với xử lý tay trên mẫu … bản ghi |
| 2 | Chạy song song với cách làm cũ ≥ 1 chu kỳ nghiệp vụ | Sai lệch = 0, hoặc mọi sai lệch giải thích được |
| 3 | Thử chạy lại | Kết quả không đổi (nếu idempotent) |
| 4 | Thử ngắt giữa chừng rồi chạy lại | Không mất, không trùng bản ghi |
Bước 4 hay bị bỏ, và nó là bước duy nhất chứng minh §2.3.5 hoạt động thật.