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

Tồn kho · inventory/listener-cogs-completion · listener

RABBIT${spring.rabbitmq.queues.cogs-completion}

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-completion — 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/CogsCompletionListener.java:34,51 → mới src/main/java/com/softdreams/easypos/warehouse/presentation/messaging/CogsCompletionConsumer.java:58-59
  • Quy tắc: R-01, R-02, R-03, R-04, R-05, R-07, R-09

Sơ đồ luồng mới (theo code thực tế)

sequenceDiagram
    participant Q as Rabbit cogs-completion (container starter, MANUAL)
    participant C as CogsCompletionConsumer
    participant A as CogsCompletionTaskService
    participant T as CogsTaskLogMongoStore
    participant S as CogsComputationService (@Transactional)
    Q->>C: onMessage(raw, taskLogId, channel)
    C->>C: sleeper.sleep(2000)
    C->>A: handle(taskLogId)
    A->>T: find(id) — findOne {_id: ObjectId|String}
    alt không có
        T-->>A: empty
        A-->>C: throw SystemException(TASK_LOG_NOT_FOUND) → ra container, không ack/nack
    else status == 1
        A-->>C: DONE → basicAck
    else
        A->>T: parseCompletion(content) (lỗi → Failure(message của cause))
        A->>A: from/to/ppuIds null → Failure(null); comId null → bỏ tính
        A->>S: calculate(ppuIds, comId, CogsTaskPeriod.toCogsPeriod(from,to)) (xem F-02)
        A->>T: markResult(id, 1,"OK" | 2,msg) — updateFirst $set status/update_time/updater=0, $set|$unset error_message
        A-->>C: SUCCESS → basicAck | FAILED → basicNack(requeue=false)
    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-completion}, containerFactory MANUAL) — L:33-34; RC:56-99 CogsCompletionConsumer.java:27-28,58; container mặc định SC:231-248 KHÁC có chủ đích (D-04, D-09)
2 APM name, RetrySynchronizationManager — L:52-57 — CHỈ CÓ Ở CŨ (D-08)
3 Thread.sleep(2000L) — L:55 CogsCompletionConsumer.java:60 (cấu hình, mặc định 2000) KHỚP (D-02)
4 findById(taskLogId) (MongoRepository<…,String>: ObjectId khi hợp lệ), không có → RuntimeException ra ngoài — L:61-65 CogsCompletionTaskService.java:40-41; CogsTaskLogMongoStore.java:52-69,100-103 KHỚP (D-01); khác loại exception, container xử lý như nhau (cùng không fatal)
5 status == 1 → ack, return — L:67-74 CogsCompletionTaskService.java:42-44; CogsCompletionConsumer.java:64-68 KHỚP
6 ObjectMapper+JavaTimeModule, tắt ADJUST_DATES…, readValue(content, CogsCompletionMessage) — L:110-115 CogsTaskLogMongoStore.java:73-79,106-111 (record CogsCompletionTask) KHỚP; text lỗi parse: F-logic-2; content "null": F-logic-1
7 calculateByPpuIds(...) trong try/catch(Exception) → status 2, e.getMessage() — L:81-89 CogsCompletionTaskService.java:55-71,75-77 KHÁC có chủ đích (D-06: lấy message của cause); kiểm null trước để giữ error_message null như NPE Java 11
8 save(taskLog) (replace, upsert; auditing update_time, updater=0) — L:90-93 CogsTaskLogMongoStore.java:82-97 (updateFirst $set/$unset) KHÁC có chủ đích (D-07); không upsert: F-logic-3
9 BaseRequestContext.clear() — L:94 — CHỈ CÓ Ở CŨ (D-08)
10 ack khi thành công / basicNack(tag,false,false) khi lỗi, catch (Exception) chỉ log — L:96-104 CogsCompletionConsumer.java:62-71 (catch IOException | ShutdownSignalException) KHỚP (exception runtime khác lúc ack/nack sẽ ra container, nhưng document đã ghi rồi nên kết quả như nhau)
11 auditor Mongo không token → creator/updater = 0 cho task log COGS_UPDATE_ASYNC — easyposconfig:…/BaseSpringSecurityAuditorAware.java:42 CogsTaskLogMongoRabbitAdapter.java:131-133 KHỚP (R-09; sửa adapter của cogs-calculate, đã ghi auto-changes.md)

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-completion ack (xong/thành công), nack không requeue (lỗi), treo khi lỗi đọc/ghi Mongo hoặc thiếu document như cũ D-01, D-03
Mongo task_log_reference (đọc) findById, chỉ theo _id findOne {_id}, chỉ theo _id không lọc type/com_id, như cũ (R-03)
Mongo task_log_reference (ghi) save replace + upsert: status, error_message (null thì mất field), update_time, updater=0 updateFirst: $set status, update_time, updater=0, $set/$unset error_message D-07; không upsert: F-logic-3
Mongo task_log_reference (COGS_UPDATE_ASYNC, do F-02 tạo) creator/updater = 0 creator/updater = 0 R-09

Transaction, khoá, idempotency, tenant

  • Ranh giới transaction: cũ chỉ calculateByPpuIds (CH:60) → mới chỉ CogsComputationService.calculate (@Transactional, gọi qua bean khác nên proxy có hiệu lực). Đọc/ghi Mongo và ack nằm ngoài transaction ở cả hai bên.
  • Khoá / cập nhật nguyên tử: cả hai không có khoá. Mới dùng $set nên không ghi đè các field khác.
  • Idempotency: chỉ dựa vào status == 1 như cũ (D-05, lệch ADR-0301 có chủ đích). Giao trùng đồng thời hoặc crash trước markResult thì tính lại, cũ cũng vậy.
  • Lọc comId: tìm task log không lọc com_id (như cũ). comId dùng để tính lấy từ content (CogsCompletionTaskService.java:62-65).

Lệch so với luồng mới đã duyệt (spec mục 6)

Không có. Code đúng như sơ đồ mục 6; có thêm parseCompletion trên port.

Dev cần chú ý khi review

Vị trí Vì sao
CogsCompletionTaskService.java:58-66 Thứ tự kiểm dữ liệu hỏng (ngày → ppuIds → comId) thay cho NPE của code cũ. task == null chưa được xử lý (F-logic-1).
CogsCompletionTaskService.java:69-77 Chỉ bắt RuntimeException. error_message lấy message của cause (D-06), nên text lỗi khác cũ.
CogsTaskLogMongoStore.java:62-68 status không phải số thì thành null và vẫn được xử lý.
CogsTaskLogMongoStore.java:82-97 Ghi $set/$unset, không upsert (D-07, F-logic-3).
CogsCompletionConsumer.java:59-71 Thiếu document hoặc lỗi Mongo thì exception ra container, message không ack (D-01). Phụ thuộc container MANUAL của starter (D-09), phải bật app.rabbitmq.activate.
CogsTaskLogMongoRabbitAdapter.java:131-133 Đổi hành vi của unit cogs-calculate: không có user thì creator/updater = 0.

F-02 Tính giá vốn từ nội dung task log

  • Điểm vào: cũ easyposasync:…/CogsCompletionListener.java:117 → easyposbase:…/services/impl/BaseCogsHistoryServiceImpl.java:61 → mới CogsCompletionTaskService.java:63-65 → CogsComputationService.java:65-66
  • Quy tắc: R-06, R-08

Sơ đồ luồng mới (theo code thực tế)

sequenceDiagram
    participant A as CogsCompletionTaskService
    participant P as CogsTaskPeriod
    participant S as CogsComputationService (@Transactional)
    participant R as CogsRelationalRepository
    participant TL as CogsTaskLogMongoRabbitAdapter
    A->>P: toCogsPeriod(from, to) — norm/quý theo zone message, from/to đổi sang giờ VN
    A->>S: calculate(ppuIds, comId, period)
    S->>R: findChildren, theo lô 100: findConvertRates, findDetailRows, findBillRows
    S->>TL: publishUpdate (requireValid comId → insert Mongo → send Rabbit) mỗi chunk 1000
    S->>TL: publishUpdate ward deltas
    S->>R: findWarehouseIds, findProductUnitIds, saveHistories (cogs_history)

Đố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 normalizedDate(from/to) theo zone của giá trị, normalizedQuarter — CH:62-65; easyposmodel:…/BaseCommon.java:2612-2615,2123-2130 CogsTaskPeriod.java:27-37,41-45 KHỚP
2 cogs_history.from/to_date = Timestamp.from(instant) (giờ JVM) — base:…/BaseCogsHistoryRepositoryCustomImpl.java:51-52; CH:662-665 CogsTaskPeriod.java:31-32 + CogsRelationalRepository.java:262-265 (giờ VN) KHÁC có chủ đích (D-09 của cogs-calculate)
3 ngày null → NPE ở normalizedDate; ppuIds null → NPE ở new HashSet<>(null) (CH:62,78) CogsCompletionTaskService.java:58-61 → Failure(null) KHỚP (cùng status 2, không có error_message)
4 comId null → mọi truy vấn com_id = null không ra dòng → không ghi, thành công (CH:70,88-100,110) CogsCompletionTaskService.java:62-66 bỏ qua calculate → SUCCESS KHỚP (riêng comId null + ppuIds rỗng: UNVERIFIED theo R-06)
5 Gộp ppu con, lô 100, gửi task log, ghi cogs_history — CH:70-124 CogsComputationService.java:65-91 (code của cogs-calculate, không đổi) KHỚP (đã review ở unit cogs-calculate)
6 Lỗi → rollback cogs_history; task log đã gửi vẫn còn — CH:60 @Transactional CogsComputationService.java:65; Mongo/Rabbit ngoài JDBC transaction KHỚP (R-08, D-05 của cogs-calculate)

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ú
product_product_unit, rs_inoutward*, bill*, inventory đọc theo com_id đọc theo com_id như cogs-calculate
config, company đọc mỗi lần gửi task log (getConfigSendQueue) SendQueueConfigRelationalAdapter.requireValid mỗi lần publish cogs-calculate D-10 (bỏ Redis)
cogs_history INSERT ppu cha, trong transaction INSERT ppu cha, trong transaction from/to theo giờ VN (D-09 cogs-calculate)
Mongo task_log_reference + Rabbit cogs-update-async insert + send trong lúc tính, không rollback như cũ creator/updater = 0 (R-09)

Transaction, khoá, idempotency, tenant

  • Ranh giới transaction: cũ @Transactional calculateByPpuIds → mới @Transactional CogsComputationService.calculate, gọi từ bean khác.
  • Khoá / cập nhật nguyên tử: không khoá. Cập nhật phiếu/hoá đơn nằm ở consumer COGS_UPDATE_ASYNC, ngoài unit này.
  • Idempotency, thời điểm phát event: task log được gửi trước khi commit, như cũ. Tính lại (giao lại message) thì gửi lại task log và INSERT thêm cogs_history, như cũ (D-05).
  • Lọc comId: mọi truy vấn và lệnh ghi dùng comId lấy từ content.

Lệch so với luồng mới đã duyệt (spec mục 6)

Không có.

Dev cần chú ý khi review

Vị trí Vì sao
CogsTaskPeriod.java:28-36 Ngày chuẩn hoá theo zone của message, nhưng from/to đổi sang giờ VN. Phải khớp với CogsRelationalRepository.java:262-263 (ghi toLocalDateTime).
CogsComputationService.java:65-91 Transaction bao cả bước gửi Mongo/Rabbit (không rollback được). Lỗi ở đây thành status 2 qua messageOf.

Nguồn của trang này

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

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