9.9 KiB
9.9 KiB
รายงานการวิเคราะห์ความเสี่ยงการหยุดทำงานของระบบ (Crash Risk Analysis)
ชุดที่ 4 (Batch 4) - Controllers 31-40
วันที่ 8 พฤษภาคม 2568
รายชื่อ Controllers ที่ตรวจสอบ (31-40)
- MainController.ts
- MyController.ts
- OrgChild1Controller.ts
- OrgChild2Controller.ts
- OrgChild3Controller.ts
- OrgChild4Controller.ts
- OrgRootController.ts
- OrganizationController.ts (ไฟล์ขนาดใหญ่ >397KB)
- OrganizationDotnetController.ts (ไฟล์ขนาดใหญ่ >329KB)
- OrganizationUnauthorizeController.ts
สรุปผลการตรวจสอบ
จำนวนปัญหาที่พบ: 8 ปัญหา
| ระดับความรุนแรง | จำนวน | ประเภท |
|---|---|---|
| 🔴 วิกฤติ | 2 | มีโอกาสทำให้ Service Crash สูงมาก |
| 🟠 สูง | 4 | มีโอกาสทำให้เกิด Unhandled Exception |
| 🟡 ปานกลาง | 2 | อาจทำให้เกิดปัญหาในสถานการณ์เฉพาะ |
รายละเอียดปัญหาแต่ละรายการ
🔴 ปัญหาที่ 1: การลบข้อมูลหลายตารางโดยไม่ใช้ Transaction (OrgRootController)
ไฟล์และตำแหน่ง:
- ไฟล์:
src/controllers/OrgRootController.ts - บรรทัด: 467-475
- Method:
delete
ประเภทปัญหา:
- Unhandled Exception - การดำเนินการหลายอย่างโดยไม่มี Transaction
สาเหตุที่ทำให้เสี่ยงต่อการ Crash:
โค้ดทำการลบข้อมูล 6 ตารางต่อเนื่องกันโดยไม่มี error handling และไม่ใช้ transaction:
- หาก delete ตัวใดตัวหนึ่งล้มเหลว ข้อมูลจะไม่สมบูรณ์
- ไม่มีการ rollback เมื่อเกิด error
- หากมี foreign key constraint violation อาจทำให้ service crash
โค้ดปัจจุบัน (มีปัญหา):
await this.empPositionRepository.remove(empPositions, { data: request });
await this.empPosMasterRepository.remove(empPosMasters, { data: request });
await this.positionRepository.remove(positions, { data: request });
await this.posMasterRepository.remove(posMasters, { data: request });
await this.child4Repository.delete({ orgRootId: id });
await this.child3Repository.delete({ orgRootId: id });
await this.child2Repository.delete({ orgRootId: id });
await this.child1Repository.delete({ orgRootId: id });
await this.orgRootRepository.delete({ id });
// ❌ ไม่มี try-catch หรือ transaction
วิธีแก้ไขที่แนะนำ:
try {
await AppDataSource.transaction(async (transactionalEntityManager) => {
await transactionalEntityManager.remove(EmployeePosition, empPositions);
await transactionalEntityManager.remove(EmployeePosMaster, empPosMasters);
await transactionalEntityManager.remove(Position, positions);
await transactionalEntityManager.remove(PosMaster, posMasters);
await transactionalEntityManager.delete(OrgChild4, { orgRootId: id });
await transactionalEntityManager.delete(OrgChild3, { orgRootId: id });
await transactionalEntityManager.delete(OrgChild2, { orgRootId: id });
await transactionalEntityManager.delete(OrgChild1, { orgRootId: id });
await transactionalEntityManager.delete(OrgRoot, { id });
});
return new HttpSuccess();
} catch (error) {
console.error('ลบข้อมูล OrgRoot ล้มเหลว:', error);
if (error.code === '23503') {
throw new HttpError(
HttpStatusCode.CONFLICT,
"ไม่สามารถลบได้ เนื่องจากมีการใช้งานข้อมูลนี้อยู่"
);
}
throw new HttpError(
HttpStatusCode.INTERNAL_SERVER_ERROR,
"เกิดข้อผิดพลาดในการลบข้อมูล"
);
}
🔴 ปัญหาที่ 2: Nested forEach กับ Async Operations (OrgRootController)
ไฟล์และตำแหน่ง:
- ไฟล์:
src/controllers/OrgRootController.ts - บรรทัด: 571-1009
- Method:
publishEmployee
ประเภทปัญหา:
- Unhandled Exception - Async operations ใน forEach ไม่ได้รับการจัดการ
สาเหตุที่ทำให้เสี่ยงต่อการ Crash:
มีการใช้ forEach ซ้อนกัน 4-5 ระดับ:
forEachไม่รอ callback ให้ทำงานเสร็จ- Promise rejections อาจไม่ได้รับการ handle
- หากเกิด error ใน nested operations อาจทำให้ unhandled rejection
🟠 ปัญหาที่ 3: Promise.all ที่ไม่มี Error Handling (OrgChild Controllers)
ไฟล์และตำแหน่ง:
- ไฟล์:
src/controllers/OrgChild1Controller.ts - บรรทัด: 105-113, 122-130, 242-250, 259-268
- Method:
save,Edit
ประเภทปัญหา:
- Missing Error Handle - Promise.all ไม่มี catch
สาเหตุที่ทำให้เสี่ยงต่อการ Crash:
มีการใช้ Promise.all หลายครั้งแต่ไม่มี error handling:
- หาก database operations fail จะเกิด unhandled rejection
- ไม่มี try-catch รอบ Promise.all
🟠 ปัญหาที่ 4-6: การลบข้อมูลหลายตารางโดยไม่ใช้ Transaction (OrgChild1-4 Controllers)
ไฟล์และตำแหน่ง:
- ไฟล์:
src/controllers/OrgChild1Controller.ts(บรรทัด 456-463) - ไฟล์:
src/controllers/OrgChild2Controller.ts(บรรทัด 317-323) - ไฟล์:
src/controllers/OrgChild3Controller.ts(บรรทัด 272-278) - ไฟล์:
src/controllers/OrgChild4Controller.ts(บรรทัด 311-315) - Method:
delete
ประเภทปัญหา:
- Unhandled Exception - การลบข้อมูลหลายตารางไม่มี Transaction
🟠 ปัญหาที่ 7: Map ที่มี Null Reference (OrgRootController)
ไฟล์และตำแหน่ง:
- ไฟล์:
src/controllers/OrgRootController.ts - บรรทัด: 446-465
- Method:
delete
ประเภทปัญหา:
- Unhandled Exception - Null reference ใน map
🟡 ปัญหาที่ 8: Missing Error Handling ใน MainController
ไฟล์และตำแหน่ง:
- ไฟล์:
src/controllers/MainController.ts - บรรทัด: 42-52
- Method:
getMainPerson
ประเภทปัญหา:
- Missing Error Handle - ไม่มี error handling
สรุปสถิติ
ปัญหาตามระดับความรุนแรง:
| ระดับ | จำนวน | ไฟล์ที่พบ |
|---|---|---|
| 🔴 วิกฤติ | 2 | OrgRootController (2) |
| 🟠 สูง | 4 | OrgRoot, OrgChild1-4Controllers |
| 🟡 ปานกลาง | 2 | MainController, OrgRootController |
ไฟล์ที่มีปัญหามากที่สุด:
- OrgRootController.ts - 4 ปัญหา (รุนแรงที่สุด)
- OrgChild1Controller.ts - 2 ปัญหา
- OrgChild2Controller.ts - 1 ปัญหา
- OrgChild3Controller.ts - 1 ปัญหา
- OrgChild4Controller.ts - 1 ปัญหา
- MainController.ts - 1 ปัญหา
ปัญหาที่พบบ่อยที่สุด:
- การลบข้อมูลหลายตารางโดยไม่ใช้ Transaction (พบ 5 ครั้ง)
- Promise.all/Async operations ไม่มี Error Handling (พบ 3 ครั้ง)
คำแนะนำเพื่อป้องกันปัญหา
1. สร้าง Transaction Wrapper Function
สร้าง utility function สำหรับ database operations หลายตาราง
2. ใช้ for...of แทน forEach สำหรับ Async Operations
// ❌ ไม่ดี
array.forEach(async (item) => {
await processItem(item);
});
// ✅ ดี
for (const item of array) {
await processItem(item);
}
3. เพิ่ม Error Handling รอบ Async Operations
ใช้ try-catch ครอบ Promise.all และ async operations ทั้งหมด
4. Enable Strict TypeScript
ตรวจสอบ tsconfig.json ให้แน่ใจว่ามีการเปิดใช้ strict mode
บันทึกเพิ่มเติม
- วันที่สร้างรายงาน: 8 พฤษภาคม 2568
- จำนวน Controllers ที่ตรวจสอบ: 10 ไฟล์ (31-40)
- เครื่องมือที่ใช้: การวิเคราะห์ Code และ Pattern Recognition
- ข้อจำกัด: OrganizationController.ts และ OrganizationDotnetController.ts มีขนาดใหญ่มาก (>300KB)
รายงานนี้ครอบคลุมเฉพาะ Controllers 31-40 สำหรับชุดที่ 4