From 5c05f1123a393f05a7978e3be208587504c1b461 Mon Sep 17 00:00:00 2001 From: Suphonchai Phoonsawat Date: Fri, 30 Jan 2026 09:49:54 +0700 Subject: [PATCH] Increase HttpClient timeout for long-running operations --- BMA.EHR.Leave/Controllers/LeaveController.cs | 499 ++++++++++--------- BMA.EHR.Leave/Program.cs | 6 +- 2 files changed, 259 insertions(+), 246 deletions(-) diff --git a/BMA.EHR.Leave/Controllers/LeaveController.cs b/BMA.EHR.Leave/Controllers/LeaveController.cs index 56e79f48..062ceab1 100644 --- a/BMA.EHR.Leave/Controllers/LeaveController.cs +++ b/BMA.EHR.Leave/Controllers/LeaveController.cs @@ -948,93 +948,114 @@ namespace BMA.EHR.Leave.Service.Controllers var fileName = $"{_bucketName}/{userId}/{currentDate.ToString("dd-MM-yyyy")}/{check_status}/{data.CheckInFileName}"; using (var ms = new MemoryStream(data.CheckInFileBytes ?? new byte[0])) { - await _minIOService.UploadFileAsync(fileName, ms); + try + { + await _minIOService.UploadFileAsync(fileName, ms); + } + catch (Exception ex) + { + await _checkInJobStatusRepository.UpdateToFailedAsync(taskId, $"ไม่สามารถอัปโหลดรูปภาพได้: {ex.Message}"); + return Error($"ไม่สามารถอัปโหลดรูปภาพได้: {ex.Message}", StatusCodes.Status500InternalServerError); + } + } - var defaultRound = await _dutyTimeRepository.GetDefaultAsync(); - if (defaultRound == null) - { - return Error("ไม่พบรอบการลงเวลาทำงาน Default", StatusCodes.Status404NotFound); - } - - var effectiveDate = await _userDutyTimeRepository.GetLastEffectRound(profile.Id, currentDate); - var roundId = effectiveDate != null ? effectiveDate.DutyTimeId : Guid.Empty; - var userRound = await _dutyTimeRepository.GetByIdAsync(roundId); - - // TODO : รอดุึงรอบที่ผูกกับ user - var duty = userRound ?? defaultRound; - - // create check in object - if (data.CheckInId == null) - { - // validate duplicate check in - var currentCheckIn = await _userTimeStampRepository.GetTimestampByDateAsync(userId, currentDate); - - if (currentCheckIn != null) + var defaultRound = await _dutyTimeRepository.GetDefaultAsync(); + if (defaultRound == null) { - return Error(new Exception("ไม่สามารถลงเวลาได้ เนื่องจากมีการลงเวลาในวันนี้แล้ว!"), StatusCodes.Status400BadRequest); + await _checkInJobStatusRepository.UpdateToFailedAsync(taskId, "ไม่พบรอบการลงเวลาทำงาน Default"); + return Error("ไม่พบรอบการลงเวลาทำงาน Default", StatusCodes.Status404NotFound); } - var checkin = new UserTimeStamp + var effectiveDate = await _userDutyTimeRepository.GetLastEffectRound(profile.Id, currentDate); + var roundId = effectiveDate != null ? effectiveDate.DutyTimeId : Guid.Empty; + var userRound = await _dutyTimeRepository.GetByIdAsync(roundId); + + // TODO : รอดุึงรอบที่ผูกกับ user + var duty = userRound ?? defaultRound; + + // create check in object + if (data.CheckInId == null) { - KeycloakUserId = userId, - CheckInLat = data.Lat, - CheckInLon = data.Lon, - IsLocationCheckIn = data.IsLocation, - CheckInLocationName = data.LocationName, - CheckInPOI = data.POI, - CheckInRemark = data.Remark, - CheckInImageUrl = fileName, - CheckIn = currentDate, - Prefix = profile.Prefix, - FirstName = profile.FirstName, - LastName = profile.LastName, - CitizenId = profile.CitizenId, + // validate duplicate check in + var currentCheckIn = await _userTimeStampRepository.GetTimestampByDateAsync(userId, currentDate); - Root = profile.Root, - Child1 = profile.Child1, - Child2 = profile.Child2, - Child3 = profile.Child3, - Child4 = profile.Child4, + if (currentCheckIn != null) + { + return Error(new Exception("ไม่สามารถลงเวลาได้ เนื่องจากมีการลงเวลาในวันนี้แล้ว!"), StatusCodes.Status400BadRequest); + } - RootId = profile.RootId, - Child1Id = profile.Child1Id, - Child2Id = profile.Child2Id, - Child3Id = profile.Child3Id, - Child4Id = profile.Child4Id, - Gender = profile.Gender, + var checkin = new UserTimeStamp + { + KeycloakUserId = userId, + CheckInLat = data.Lat, + CheckInLon = data.Lon, + IsLocationCheckIn = data.IsLocation, + CheckInLocationName = data.LocationName, + CheckInPOI = data.POI, + CheckInRemark = data.Remark, + CheckInImageUrl = fileName, + CheckIn = currentDate, + Prefix = profile.Prefix, + FirstName = profile.FirstName, + LastName = profile.LastName, + CitizenId = profile.CitizenId, - ProfileId = profile.Id, - ProfileType = profile.ProfileType, + Root = profile.Root, + Child1 = profile.Child1, + Child2 = profile.Child2, + Child3 = profile.Child3, + Child4 = profile.Child4, - RootDnaId = profile.RootDnaId, - Child1DnaId = profile.Child1DnaId, - Child2DnaId = profile.Child2DnaId, - Child3DnaId = profile.Child3DnaId, - Child4DnaId = profile.Child4DnaId, - }; + RootId = profile.RootId, + Child1Id = profile.Child1Id, + Child2Id = profile.Child2Id, + Child3Id = profile.Child3Id, + Child4Id = profile.Child4Id, + Gender = profile.Gender, - var startTime = ""; - var endTime = ""; - if (!data.IsLocation && data.LocationName == "ไปประชุม / อบรม / สัมมนา") - { - //startTime = "09:30"; - startTime = "10:30"; - endTime = "12:00"; - } - else - { - startTime = duty.StartTimeMorning; - endTime = duty.EndTimeMorning; - } + ProfileId = profile.Id, + ProfileType = profile.ProfileType, - string checkInStatus = "NORMAL"; - var leaveReq = await _leaveRequestRepository.GetLeavePeriodAsync(userId, currentDate.Date); - if (leaveReq != null) - { - var leaveRange = leaveReq.LeaveRange == null ? "" : leaveReq.LeaveRange.ToUpper(); - if (leaveRange == "MORNING" || leaveRange == "ALL") - checkInStatus = "NORMAL"; + RootDnaId = profile.RootDnaId, + Child1DnaId = profile.Child1DnaId, + Child2DnaId = profile.Child2DnaId, + Child3DnaId = profile.Child3DnaId, + Child4DnaId = profile.Child4DnaId, + }; + + var startTime = ""; + var endTime = ""; + if (!data.IsLocation && data.LocationName == "ไปประชุม / อบรม / สัมมนา") + { + //startTime = "09:30"; + startTime = "10:30"; + endTime = "12:00"; + } + else + { + startTime = duty.StartTimeMorning; + endTime = duty.EndTimeMorning; + } + + string checkInStatus = "NORMAL"; + var leaveReq = await _leaveRequestRepository.GetLeavePeriodAsync(userId, currentDate.Date); + if (leaveReq != null) + { + var leaveRange = leaveReq.LeaveRange == null ? "" : leaveReq.LeaveRange.ToUpper(); + if (leaveRange == "MORNING" || leaveRange == "ALL") + checkInStatus = "NORMAL"; + else + { + checkInStatus = DateTime.Parse(currentDate.ToString("yyyy-MM-dd HH:mm")) > + DateTime.Parse($"{currentDate.ToString("yyyy-MM-dd")} {startTime}") ? + DateTime.Parse(currentDate.ToString("yyyy-MM-dd HH:mm")) > + DateTime.Parse($"{currentDate.ToString("yyyy-MM-dd")} {duty.EndTimeMorning}") ? + "ABSENT" : + "LATE" : + "NORMAL"; + } + } else { checkInStatus = DateTime.Parse(currentDate.ToString("yyyy-MM-dd HH:mm")) > @@ -1045,123 +1066,127 @@ namespace BMA.EHR.Leave.Service.Controllers "LATE" : "NORMAL"; } - } - else - { - checkInStatus = DateTime.Parse(currentDate.ToString("yyyy-MM-dd HH:mm")) > - DateTime.Parse($"{currentDate.ToString("yyyy-MM-dd")} {startTime}") ? - DateTime.Parse(currentDate.ToString("yyyy-MM-dd HH:mm")) > - DateTime.Parse($"{currentDate.ToString("yyyy-MM-dd")} {duty.EndTimeMorning}") ? - "ABSENT" : - "LATE" : - "NORMAL"; - } - + - // process - รอทำใน queue - var checkin_process = new ProcessUserTimeStamp - { - KeycloakUserId = userId, - CheckInLat = data.Lat, - CheckInLon = data.Lon, - IsLocationCheckIn = data.IsLocation, - CheckInLocationName = data.LocationName, - CheckInPOI = data.POI, - CheckInRemark = data.Remark, - CheckInImageUrl = fileName, - CheckIn = currentDate, - CheckInStatus = checkInStatus, - Prefix = profile.Prefix, - FirstName = profile.FirstName, - LastName = profile.LastName, - CitizenId = profile.CitizenId, - - Root = profile.Root, - Child1 = profile.Child1, - Child2 = profile.Child2, - Child3 = profile.Child3, - Child4 = profile.Child4, - - RootId = profile.RootId, - Child1Id = profile.Child1Id, - Child2Id = profile.Child2Id, - Child3Id = profile.Child3Id, - Child4Id = profile.Child4Id, - Gender = profile.Gender, - - ProfileId = profile.Id, - ProfileType = profile.ProfileType, - - - RootDnaId = profile.RootDnaId, - Child1DnaId = profile.Child1DnaId, - Child2DnaId = profile.Child2DnaId, - Child3DnaId = profile.Child3DnaId, - Child4DnaId = profile.Child4DnaId, - }; - - await _userTimeStampRepository.AddAsync(checkin); - await _processUserTimeStampRepository.AddAsync(checkin_process); - } - else - { - var checkout = await _userTimeStampRepository.GetByIdAsync(data.CheckInId.Value); - - var currentCheckInProcess = await _processUserTimeStampRepository.GetTimestampByDateAsync(userId, checkout.CheckIn.Date); - - var checkout_process = await _processUserTimeStampRepository.GetByIdAsync(currentCheckInProcess.Id); - - - if (checkout != null) - { - checkout.CheckOutLat = data.Lat; - checkout.CheckOutLon = data.Lon; - checkout.IsLocationCheckOut = data.IsLocation; - checkout.CheckOutLocationName = data.LocationName; - checkout.CheckOutPOI = data.POI; - checkout.CheckOutRemark = data.Remark; - checkout.CheckOutImageUrl = fileName; - checkout.CheckOut = currentDate; - - await _userTimeStampRepository.UpdateAsync(checkout); - } - else - { - return Error(new Exception(GlobalMessages.DataNotFound), StatusCodes.Status404NotFound); - } - - var endTime = ""; - var startTime = ""; - var endTimeMorning = ""; - if (!data.IsLocation && data.LocationName == "ไปประชุม / อบรม / สัมมนา") - { - startTime = "13:00"; - endTime = "14:30"; - endTimeMorning = "12:00"; - } - else - { - endTime = duty.EndTimeAfternoon; - startTime = duty.StartTimeAfternoon; - endTimeMorning = duty.EndTimeMorning; - } - - - - string checkOutStatus = "NORMAL"; - var leaveReq = await _leaveRequestRepository.GetLeavePeriodAsync(userId, currentDate.Date); - if (leaveReq != null) - { - var leaveRange = leaveReq.LeaveRangeEnd == null ? "" : leaveReq.LeaveRangeEnd.ToUpper(); - if (leaveRange == "AFTERNOON" || leaveRange == "ALL") + // process - รอทำใน queue + var checkin_process = new ProcessUserTimeStamp { - if(DateTime.Parse(currentDate.ToString("yyyy-MM-dd HH:mm")) < - DateTime.Parse($"{currentDate.ToString("yyyy-MM-dd")} {endTimeMorning}")) - checkOutStatus = "ABSENT"; - else - checkOutStatus = "NORMAL"; + KeycloakUserId = userId, + CheckInLat = data.Lat, + CheckInLon = data.Lon, + IsLocationCheckIn = data.IsLocation, + CheckInLocationName = data.LocationName, + CheckInPOI = data.POI, + CheckInRemark = data.Remark, + CheckInImageUrl = fileName, + CheckIn = currentDate, + CheckInStatus = checkInStatus, + Prefix = profile.Prefix, + FirstName = profile.FirstName, + LastName = profile.LastName, + CitizenId = profile.CitizenId, + + Root = profile.Root, + Child1 = profile.Child1, + Child2 = profile.Child2, + Child3 = profile.Child3, + Child4 = profile.Child4, + + RootId = profile.RootId, + Child1Id = profile.Child1Id, + Child2Id = profile.Child2Id, + Child3Id = profile.Child3Id, + Child4Id = profile.Child4Id, + Gender = profile.Gender, + + ProfileId = profile.Id, + ProfileType = profile.ProfileType, + + + RootDnaId = profile.RootDnaId, + Child1DnaId = profile.Child1DnaId, + Child2DnaId = profile.Child2DnaId, + Child3DnaId = profile.Child3DnaId, + Child4DnaId = profile.Child4DnaId, + }; + + await _userTimeStampRepository.AddAsync(checkin); + await _processUserTimeStampRepository.AddAsync(checkin_process); + } + else + { + var checkout = await _userTimeStampRepository.GetByIdAsync(data.CheckInId.Value); + + var currentCheckInProcess = await _processUserTimeStampRepository.GetTimestampByDateAsync(userId, checkout.CheckIn.Date); + + var checkout_process = await _processUserTimeStampRepository.GetByIdAsync(currentCheckInProcess.Id); + + + if (checkout != null) + { + checkout.CheckOutLat = data.Lat; + checkout.CheckOutLon = data.Lon; + checkout.IsLocationCheckOut = data.IsLocation; + checkout.CheckOutLocationName = data.LocationName; + checkout.CheckOutPOI = data.POI; + checkout.CheckOutRemark = data.Remark; + checkout.CheckOutImageUrl = fileName; + checkout.CheckOut = currentDate; + + await _userTimeStampRepository.UpdateAsync(checkout); } else + { + await _checkInJobStatusRepository.UpdateToFailedAsync(taskId, "ไม่พบข้อมูลการลงเวลาทำงาน"); + return Error(new Exception(GlobalMessages.DataNotFound), StatusCodes.Status404NotFound); + } + + var endTime = ""; + var startTime = ""; + var endTimeMorning = ""; + if (!data.IsLocation && data.LocationName == "ไปประชุม / อบรม / สัมมนา") + { + startTime = "13:00"; + endTime = "14:30"; + endTimeMorning = "12:00"; + } + else + { + endTime = duty.EndTimeAfternoon; + startTime = duty.StartTimeAfternoon; + endTimeMorning = duty.EndTimeMorning; + } + string checkOutStatus = "NORMAL"; + var leaveReq = await _leaveRequestRepository.GetLeavePeriodAsync(userId, currentDate.Date); + if (leaveReq != null) + { + var leaveRange = leaveReq.LeaveRangeEnd == null ? "" : leaveReq.LeaveRangeEnd.ToUpper(); + if (leaveRange == "AFTERNOON" || leaveRange == "ALL") + { + if(DateTime.Parse(currentDate.ToString("yyyy-MM-dd HH:mm")) < + DateTime.Parse($"{currentDate.ToString("yyyy-MM-dd")} {endTimeMorning}")) + checkOutStatus = "ABSENT"; + else + checkOutStatus = "NORMAL"; + } + else + { + // fix issue : SIT ระบบบันทึกเวลาปฏิบัติงาน>>ลงเวลาเข้า-ออกงาน (กรณีลงเวลาออกอีกวัน) #921 + checkOutStatus = DateTime.Parse(currentDate.ToString("yyyy-MM-dd HH:mm")) < + DateTime.Parse($"{currentDate.ToString("yyyy-MM-dd")} {duty.EndTimeAfternoon}") ? + // "ABSENT" : + checkout.CheckIn.Date < currentDate.Date ? "NORMAL" : + DateTime.Parse(currentDate.ToString("yyyy-MM-dd HH:mm")) >= + DateTime.Parse($"{currentDate.ToString("yyyy-MM-dd")} {endTime}") ? + "NORMAL" : + "ABSENT" : + DateTime.Parse(currentDate.ToString("yyyy-MM-dd HH:mm")) < + DateTime.Parse($"{currentDate.ToString("yyyy-MM-dd")} {endTimeMorning}") ? + "ABSENT" : + "NORMAL"; + } + } + else { // fix issue : SIT ระบบบันทึกเวลาปฏิบัติงาน>>ลงเวลาเข้า-ออกงาน (กรณีลงเวลาออกอีกวัน) #921 checkOutStatus = DateTime.Parse(currentDate.ToString("yyyy-MM-dd HH:mm")) < @@ -1176,71 +1201,55 @@ namespace BMA.EHR.Leave.Service.Controllers DateTime.Parse($"{currentDate.ToString("yyyy-MM-dd")} {endTimeMorning}") ? "ABSENT" : "NORMAL"; - } - } - else - { - // fix issue : SIT ระบบบันทึกเวลาปฏิบัติงาน>>ลงเวลาเข้า-ออกงาน (กรณีลงเวลาออกอีกวัน) #921 - checkOutStatus = DateTime.Parse(currentDate.ToString("yyyy-MM-dd HH:mm")) < - DateTime.Parse($"{currentDate.ToString("yyyy-MM-dd")} {duty.EndTimeAfternoon}") ? - // "ABSENT" : - checkout.CheckIn.Date < currentDate.Date ? "NORMAL" : - DateTime.Parse(currentDate.ToString("yyyy-MM-dd HH:mm")) >= - DateTime.Parse($"{currentDate.ToString("yyyy-MM-dd")} {endTime}") ? - "NORMAL" : - "ABSENT" : - DateTime.Parse(currentDate.ToString("yyyy-MM-dd HH:mm")) < - DateTime.Parse($"{currentDate.ToString("yyyy-MM-dd")} {endTimeMorning}") ? - "ABSENT" : - "NORMAL"; - } + } - if (checkout_process != null) - { - checkout_process.CheckOutLat = data.Lat; - checkout_process.CheckOutLon = data.Lon; - checkout_process.IsLocationCheckOut = data.IsLocation; - checkout_process.CheckOutLocationName = data.LocationName; - checkout_process.CheckOutPOI = data.POI; - checkout_process.CheckOutRemark = data.Remark; - checkout_process.CheckOutImageUrl = fileName; - checkout_process.CheckOut = currentDate; - checkout_process.CheckOutStatus = checkOutStatus; + if (checkout_process != null) + { + checkout_process.CheckOutLat = data.Lat; + checkout_process.CheckOutLon = data.Lon; + checkout_process.IsLocationCheckOut = data.IsLocation; + checkout_process.CheckOutLocationName = data.LocationName; + checkout_process.CheckOutPOI = data.POI; + checkout_process.CheckOutRemark = data.Remark; + checkout_process.CheckOutImageUrl = fileName; + checkout_process.CheckOut = currentDate; + checkout_process.CheckOutStatus = checkOutStatus; + + await _processUserTimeStampRepository.UpdateAsync(checkout_process); + } + else + { + await _checkInJobStatusRepository.UpdateToFailedAsync(taskId, "ไม่พบข้อมูลการประมวลผลเวลาทำงาน"); + return Error(new Exception(GlobalMessages.DataNotFound), StatusCodes.Status404NotFound); + } - await _processUserTimeStampRepository.UpdateAsync(checkout_process); - } - else - { - return Error(new Exception(GlobalMessages.DataNotFound), StatusCodes.Status404NotFound); } - } - - // อัปเดตสถานะเป็น COMPLETED - if (taskId != Guid.Empty) - { - var additionalData = JsonConvert.SerializeObject(new + // อัปเดตสถานะเป็น COMPLETED + if (taskId != Guid.Empty) { - CheckInType = data.CheckInId == null ? "check-in" : "check-out", - FileName = fileName, - ProcessedDate = currentDate - }); - await _checkInJobStatusRepository.UpdateToCompletedAsync(taskId, additionalData); - } + var additionalData = JsonConvert.SerializeObject(new + { + CheckInType = data.CheckInId == null ? "check-in" : "check-out", + FileName = fileName, + ProcessedDate = currentDate + }); + await _checkInJobStatusRepository.UpdateToCompletedAsync(taskId, additionalData); + } - var checkInType = data.CheckInId == null ? "check-in" : "check-out"; - return Success(new { user = $"{profile.FirstName} {profile.LastName}", date = currentDate, type = checkInType }); ; - } - catch (Exception ex) - { - // อัปเดตสถานะเป็น FAILED - if (taskId != Guid.Empty) - { - await _checkInJobStatusRepository.UpdateToFailedAsync(taskId, ex.Message); + var checkInType = data.CheckInId == null ? "check-in" : "check-out"; + return Success(new { user = $"{profile.FirstName} {profile.LastName}", date = currentDate, type = checkInType }); ; + } + catch (Exception ex) + { + // อัปเดตสถานะเป็น FAILED + if (taskId != Guid.Empty) + { + await _checkInJobStatusRepository.UpdateToFailedAsync(taskId, ex.Message); + } + throw; } - throw; } - } /// /// LV1_005 - ลงเวลาเข้า-ออกงาน (USER) diff --git a/BMA.EHR.Leave/Program.cs b/BMA.EHR.Leave/Program.cs index 928c8fc2..1b868cfb 100644 --- a/BMA.EHR.Leave/Program.cs +++ b/BMA.EHR.Leave/Program.cs @@ -96,7 +96,11 @@ builder.Services.AddPersistence(builder.Configuration); builder.Services.AddLeavePersistence(builder.Configuration); builder.Services.AddTransient(); -builder.Services.AddHttpClient(); +// Configure HttpClient with increased timeout for long-running operations (e.g., RabbitMQ Management API) +builder.Services.AddHttpClient(client => +{ + client.Timeout = TimeSpan.FromMinutes(10); // Set timeout to 10 minutes +}); builder.Services.AddControllers(options => {