690417:1538 Refactor Work flow ADR-021

This commit is contained in:
2026-04-17 15:38:20 +07:00
parent 6d45bdaeb5
commit 3a5fc8d4af
23 changed files with 892 additions and 135 deletions
@@ -1,6 +1,8 @@
// File: src/modules/workflow-engine/workflow-engine.service.ts
import { Injectable, Logger } from '@nestjs/common';
import { Injectable, Inject, Logger } from '@nestjs/common';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import type { Cache } from 'cache-manager';
import { NotFoundException, WorkflowException } from '../../common/exceptions';
import { InjectRepository } from '@nestjs/typeorm';
import { DataSource, In, Repository } from 'typeorm';
@@ -55,7 +57,8 @@ export class WorkflowEngineService {
private readonly attachmentRepo: Repository<Attachment>,
private readonly dslService: WorkflowDslService,
private readonly eventService: WorkflowEventService, // [NEW] Inject Service
private readonly dataSource: DataSource // ใช้สำหรับ Transaction
private readonly dataSource: DataSource, // ใช้สำหรับ Transaction
@Inject(CACHE_MANAGER) private readonly cacheManager: Cache // ADR-021 T024: History cache
) {}
// =================================================================
@@ -215,12 +218,18 @@ export class WorkflowEngineService {
}
// 3. สร้าง Instance
// [C3] Extract contractId from context to persist as searchable column
const contractId =
typeof initialContext.contractId === 'number'
? initialContext.contractId
: null;
const instance = this.instanceRepo.create({
definition,
entityType,
entityId,
currentState: initialState,
status: WorkflowStatus.ACTIVE,
contractId,
context: initialContext,
});
@@ -364,19 +373,22 @@ export class WorkflowEngineService {
payload,
},
});
await queryRunner.manager.save(history);
const savedHistory = await queryRunner.manager.save(history);
// ADR-021: ผูกไฟล์แนบประจำ Step นี้ (ทำในตัว Transaction เดียวกัน)
if (attachmentPublicIds && attachmentPublicIds.length > 0) {
await queryRunner.manager.update(
Attachment,
{ publicId: In(attachmentPublicIds) },
{ workflowHistoryId: history.id }
{ workflowHistoryId: savedHistory.id }
);
}
await queryRunner.commitTransaction();
// ADR-021 T043: Invalidate Workflow History cache หลัง transition สำเร็จ
void this.cacheManager.del(`wf:history:${instanceId}`);
// [NEW] เก็บค่าไว้ Dispatch หลัง Commit
eventsToDispatch = evaluation.events;
updatedContext = context;
@@ -443,6 +455,12 @@ export class WorkflowEngineService {
async getHistoryWithAttachments(
instanceId: string
): Promise<WorkflowHistoryItemDto[]> {
// ADR-021 T024: Redis cache — ป้องกัน N+1 บน repeated view (TTL 1h)
const cacheKey = `wf:history:${instanceId}`;
const cached =
await this.cacheManager.get<WorkflowHistoryItemDto[]>(cacheKey);
if (cached) return cached;
const histories = await this.historyRepo.find({
where: { instanceId },
order: { createdAt: 'ASC' },
@@ -474,7 +492,7 @@ export class WorkflowEngineService {
{}
);
return histories.map((h) => ({
const result: WorkflowHistoryItemDto[] = histories.map((h) => ({
id: h.id,
fromState: h.fromState,
toState: h.toState,
@@ -490,6 +508,10 @@ export class WorkflowEngineService {
})),
createdAt: h.createdAt.toISOString(),
}));
// Cache result (TTL 1h = 3_600_000 ms)
await this.cacheManager.set(cacheKey, result, 3_600_000);
return result;
}
// =================================================================