Phân tích luồng sau chuyển — inventory/listener-cogs-update-async — vòng 1
F-01 Nhận message, đọc task log, ghi kết quả, ack/nack
- Điểm vào: cũ
easyposasync:src/main/java/sds/ep/async/queueListener/CogsUpdateAsyncListener.java:44-45→ mớisrc/main/java/com/softdreams/easypos/warehouse/presentation/messaging/CogsUpdateAsyncConsumer.java:61-62 - Quy tắc: R-01, R-02, R-05
Sơ đồ luồng mới (theo code thực tế)
sequenceDiagram
participant Q as Rabbit cogs-update-async
participant C as CogsUpdateAsyncConsumer.onMessage
participant A as CogsUpdateTaskService.handle
participant T as CogsTaskLogMongoStore
participant B as CogsBatchUpdateService.apply (@Transactional)
Q->>C: (Message, taskLogId, Channel)
C->>C: sleeper.sleep(2000)
C->>A: handle(taskLogId)
A->>T: find(id) (_id, ObjectId nếu hợp lệ)
alt không có
A-->>C: SystemException TASK_LOG_NOT_FOUND → ném ra container, không ack
else status == 1
A-->>C: DONE → basicAck
else
A->>T: parseUpdate(content)
alt lỗi Jackson / content null
A->>T: markResult(id, 2, cause.getMessage())
A-->>C: FAILED → basicNack(requeue=false)
else
A->>B: apply(update)
alt RuntimeException
A->>T: markResult(id, 2, NPE→"java.lang.NullPointerException" | cause.toString() | toString())
A-->>C: FAILED → basicNack(requeue=false)
else OK
A->>T: markResult(id, 1, "OK") ($set status, error_message, update_time, updater 0)
A-->>C: SUCCESS → basicAck
end
end
end
Đối chiếu từng bước
| # | Luồng cũ (repo:path:dòng) |
Luồng mới (path:dòng) |
Kết luận |
|---|---|---|---|
| 1 | @ConditionalOnProperty + @RabbitListener(queues=${spring.rabbitmq.queues.cogs-update-async}, containerFactory) — L:30-32 |
CogsUpdateAsyncConsumer.java:26-27,61, container mặc định của starter, property app.rabbitmq.queues.cogs-update-async |
KHÁC có chủ đích (D-01 → D-04, D-09 của LC) |
| 2 | Bật APM transaction — L:47-48 |
không có | KHÁC có chủ đích (D-01 → D-08 của LC) |
| 3 | Thread.sleep(2000) — L:49 |
CogsUpdateAsyncConsumer.java:63 (listener-delay-ms, mặc định 2000) |
KHỚP |
| 4 | findById, không có → RuntimeException, không ack — L:57-61 |
CogsUpdateTaskService.java:41-42; CogsTaskLogMongoStore.java:53-71 |
KHỚP (treo message: D-01) |
| 5 | status == 1 → ack — L:63-70 |
CogsUpdateTaskService.java:43-44; CogsUpdateAsyncConsumer.java:70 |
KHỚP |
| 6 | readValue(content, CogsBatchUpdateMessage) + JavaTimeModule; lỗi → e.getMessage() — L:79-85,94-97 |
CogsTaskLogMongoStore.java:83-89 (mapper :116-121); CogsUpdateTaskService.java:47-52 lấy cause.getMessage() |
KHỚP: record mới cùng key, FAIL_ON_UNKNOWN_PROPERTIES như cũ. Text lỗi Jackson có thể khác theo phiên bản (D-06) |
| 7 | processAsyncCogsUpdate lỗi → e.getMessage() của RuntimeException bọc ngoài, tức e.toString() — CH:245-247, L:94-97 |
CogsUpdateTaskService.java:53-57,68-73 |
KHỚP (D-06) cho lỗi trong thân method. Lỗi ở tầng transaction thì KHÁC (F-logic-1) |
| 8 | save(taskLog) cả document, auditing update_time, updater — L:102-105 |
CogsTaskLogMongoStore.java:92-107 $set |
KHÁC có chủ đích (D-01 → D-07 của LC) |
| 9 | ack/nack(requeue=false), lỗi ack chỉ log — L:108-116 |
CogsUpdateAsyncConsumer.java:66-74 |
KHỚP |
| 10 | Lỗi ghi Mongo → ném ra container, không ack — L:105 |
markResult ném SystemException ra ngoài handle → không ack |
KHỚP |
Dữ liệu và side effect
| Bảng / topic / cache | Cũ (đọc/ghi, điều kiện) | Mới (đọc/ghi, điều kiện) | Ghi chú |
|---|---|---|---|
Rabbit cogs-update-async |
ack khi xong/đã xong, nack(false,false) khi lỗi | như cũ | tên queue ở dev (cogs_update_async) phải cấu hình qua app.rabbitmq.queues.cogs-update-async, giống LC |
Mongo task_log_reference |
đọc theo _id; ghi lại cả document |
đọc theo _id; $set status, error_message, update_time, updater 0 |
D-07 của LC |
Transaction, khoá, idempotency, tenant
- Ranh giới transaction: cũ thì listener không có transaction, chỉ
processAsyncCogsUpdatecó. Mới thìhandlekhông có, chỉapplycó, gọi qua bean khác nên proxy hoạt động. Ghi Mongo nằm sau commit, giống cũ. - Khoá / cập nhật nguyên tử: không có ở bước này.
- Idempotency: cả hai chỉ dựa vào
status == 1, không dùngIdempotencyStore(D-02). - Lọc
comId:findkhông lọccom_id/type, giống cũ.
Lệch so với luồng mới đã duyệt (spec mục 6)
không
Dev cần chú ý khi review
| Vị trí | Vì sao |
|---|---|
CogsUpdateTaskService.java:68-73 |
Quy đổi exception thành error_message. Lỗi ở tầng transaction thì text khác cũ (F-logic-1) |
CogsUpdateTaskService.java:58 |
Ghi status 1 sau khi DB đã commit. Crash hoặc Mongo lỗi giữa hai bước → message giao lại, cộng chênh lệch lần nữa (R-04, D-04) |
F-02 Áp cập nhật đơn giá / tiền vào phiếu, hoá đơn, lệnh huỷ
- Điểm vào: cũ
easyposbase:src/main/java/sds/ep/baseservice/services/impl/BaseCogsHistoryServiceImpl.java:225-227→ mớisrc/main/java/com/softdreams/easypos/warehouse/application/cogs/CogsBatchUpdateService.java:37-38 - Quy tắc: R-03, R-04
Sơ đồ luồng mới (theo code thực tế)
sequenceDiagram
participant B as CogsBatchUpdateService.apply (@Transactional)
participant R as CogsUpdateRelationalRepository (JdbcTemplate)
B->>B: update.targetTable() (update null → NPE)
opt RS_INOUTWARD_DETAIL và detailUpdates không rỗng
B->>B: sortedById (id/phần tử null → NPE)
B->>R: updateDetails(sorted) → batchUpdate UPDATE rs_inoutward_detail … WHERE id=?
B->>R: syncProductionOrderPrices(id theo thứ tự gốc) → UPDATE pod … FROM … WHERE rid.id IN (?…)
end
opt BILL_PRODUCT và billUpdates không rỗng
B->>R: updateBills(sorted) → batchUpdate UPDATE bill_product …
end
opt RS_INOUTWARD và wardUpdates không rỗng
B->>R: addWardDeltas(sorted) → batchUpdate UPDATE rs_inoutward SET amount = ISNULL(amount,0)+? …
end
Note over R: DataAccessException → SystemException(EXCEPTION_ERROR, cause) → rollback
Đối chiếu từng bước
| # | Luồng cũ (repo:path:dòng) |
Luồng mới (path:dòng) |
Kết luận |
|---|---|---|---|
| 1 | @Transactional processAsyncCogsUpdate, ba if độc lập — CH:225-243 |
CogsBatchUpdateService.java:37-53 |
KHỚP |
| 2 | Hằng bảng — easyposmodel:…/BaseConstants.java:386-388 |
CogsBatchUpdate.java:21-25 |
KHỚP |
| 3 | Sắp theo id tăng dần trong repository — CR:74-75,113-114,149-150 |
CogsBatchUpdateService.java:60-64 |
KHỚP: NPE khi id hoặc phần tử null, với list từ 2 phần tử |
| 4 | UPDATE rs_inoutward_detail …, setBigDecimal ×4, setInt — CR:79-95 |
CogsUpdateRelationalRepository.java:29-31,61-74 |
KHỚP: null → setNull(DECIMAL); id().intValue() NPE như setInt |
| 5 | Đồng bộ production_order_detail theo id thứ tự gốc — CH:232-235, CR:183-201 |
CogsBatchUpdateService.java:43-45; CogsUpdateRelationalRepository.java:36-46,77-84 |
KHỚP: SQL giống từng ký tự, cách bind giống (UNVERIFIED trên MSSQL, K-13) |
| 6 | UPDATE bill_product … — CR:118-132 |
CogsUpdateRelationalRepository.java:32,87-98 |
KHỚP |
| 7 | UPDATE rs_inoutward SET amount = ISNULL(amount,0)+? … — CR:155-170 |
CogsUpdateRelationalRepository.java:33-35,101-112 |
KHỚP: delta null → NULL (D-04) |
| 8 | Mọi lỗi bọc RuntimeException(e) → rollback — CH:245-247 |
Adapter bọc SystemException(cause), NPE để nguyên; đều rollback |
KHỚP về rollback. Text lỗi: D-06, F-logic-1 |
| 9 | Đếm số dòng tác động, chỉ để log — CR:97-105 |
không có | KHÁC, không ảnh hưởng hành vi |
Dữ liệu và side effect
| Bảng / topic / cache | Cũ | Mới | Ghi chú |
|---|---|---|---|
rs_inoutward_detail |
ghi 4 cột theo id, batch |
như cũ | không lọc com_id (D-03) |
production_order_detail |
ghi unit_price qua join type_doc 3 |
như cũ | transitional (D-05) |
bill_product |
ghi purchase_price, total_cogs theo id |
như cũ | D-05 |
rs_inoutward |
cộng delta vào amount, total_amount |
như cũ | không idempotent (D-04, D-07) |
Transaction, khoá, idempotency, tenant
- Ranh giới transaction: cũ bao trọn
processAsyncCogsUpdate, mới bao trọnCogsBatchUpdateService.apply; JdbcTemplate dùng chung connection vớiJpaTransactionManager. - Khoá: UPDATE nguyên tử ở DB; thứ tự id tăng dần như cũ.
- Idempotency: cộng delta hai lần nếu giao lại sau commit, giống cũ (R-04, D-04). Không phát event.
- Lọc
comId: không có ở cả hai bên (D-03).
Lệch so với luồng mới đã duyệt (spec mục 6)
không
Dev cần chú ý khi review
| Vị trí | Vì sao |
|---|---|
CogsUpdateRelationalRepository.java:36-46,77-84 |
UPDATE … FROM … JOIN riêng của SQL Server; test chỉ so chuỗi SQL (K-13) |
CogsUpdateRelationalRepository.java:101-112 |
Cộng dồn tiền phiếu, không chống lặp (D-04, D-07) |
CogsBatchUpdateService.java:41-45 |
Ghi hai bảng trong một transaction; đồng bộ dùng id thứ tự gốc, đọc lại đơn giá vừa ghi |
CogsUpdateRelationalRepository.java:61-74,87-98,101-112 |
Chỉ bắt DataAccessException; NPE để nguyên để ra đúng text "java.lang.NullPointerException" |