Báo cáo chuyển đổi warehouse-service

Tồn kho · inventory/listener-cogs-update-async · listener

RABBIT${spring.rabbitmq.queues.cogs-update-async}

Vòng
1
Cổng G1–G6
PENDING_SONAR
Bước
sonar-check
Nhánh đích
feat/thongpd/migrate-inventory-ws1

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ới src/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ỉ processAsyncCogsUpdate có. Mới thì handle không có, chỉ apply có, 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ùng IdempotencyStore (D-02).
  • Lọc comId: find không lọc com_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ới src/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ọn CogsBatchUpdateService.apply; JdbcTemplate dùng chung connection với JpaTransactionManager.
  • 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"

Nguồn của trang này

  • Phân tích luồng migrations/inventory/listener-cogs-update-async/verify/round-1/flow-analysis.md vòng 1 · sha256 1bed2445bf7b

v1 dựng 2026-11-06 00:42 · base commit đích a06ccfa6d4