using FrameworkBLL.SchedulerTaskGenerator; using FrameworkDAL.CustomCode.Scheduler; using FrameworkDAL.CustomCode.SchedulerTaskGenerator; using FrameworkDAL.DTO.Scheduler; using GB5Shared.DTO.Framework.AutoNumber; using GB5Shared.DTO.Framework.Criteria; using GB5Shared.DTO.Framework.Login; using GB5Shared.GenerateAutoNumber; using GB5Shared.Resource.Response; using GB5Shared.Validation; using Microsoft.Extensions.Logging; using System; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading.Tasks; namespace FrameworkBLL.Scheduler { public class SchedulerBLL : ISchedulerBLL { private readonly ISchedulerDAL _SchedulerDAL; private readonly AutoNumber _AutoNumber; private readonly IValidation _Validation; private readonly IQuartzSyncService _QuartzSyncService; private readonly ISchedulerTaskDAL _SchedulerTaskDAL; private readonly ILogger _Logger; public SchedulerBLL( ISchedulerDAL SchedulerDAL, AutoNumber AutoNumber, IValidation Validation, IQuartzSyncService QuartzSyncService, ISchedulerTaskDAL SchedulerTaskDAL, ILogger Logger) { _SchedulerDAL = SchedulerDAL; _AutoNumber = AutoNumber; _Validation = Validation; _QuartzSyncService = QuartzSyncService; _SchedulerTaskDAL = SchedulerTaskDAL; _Logger = Logger; } // A schedule-only edit (e.g. cron changed) must resync Quartz for every job // pointing at this SchedulerId, even though MJOBDEFINE itself didn't change. // Failure here must not fail the scheduler save — the row is already committed. private async Task ResyncJobsForSchedulerAsync(int schedulerId, LoginDTO login) { try { var jobIds = await _SchedulerTaskDAL.GetJobIdsBySchedulerIdAsync(schedulerId, login); foreach (var jobId in jobIds) { try { await _QuartzSyncService.SyncJobAsync(jobId, login); } catch (Exception ex) { _Logger.LogWarning(ex, "SchedulerBLL: QuartzSyncService.SyncJobAsync failed for JobId={JobId} (SchedulerId={SchedulerId})", jobId, schedulerId); } } } catch (Exception ex) { _Logger.LogWarning(ex, "SchedulerBLL: failed to load JobIds for SchedulerId={SchedulerId} — Quartz triggers not resynced", schedulerId); } } public Task GetScheduler(int SchedulerId, LoginDTO LoginDTO) => _SchedulerDAL.GetScheduler(SchedulerId, LoginDTO); public async Task SaveScheduler(SchedulerDTO SchedulerDTO, LoginDTO LoginDTO) { if (SchedulerDTO == null) throw new ArgumentNullException(nameof(SchedulerDTO)); AutoNumberDTO? autoNumberDTO = null; try { await _Validation.NotEmpty(SchedulerDTO.SchedulerName, nameof(SchedulerDTO.SchedulerName)); SchedulerDTO.SchedulerModifiedById = LoginDTO.UserId; SchedulerDTO.SchedulerModifiedOn = DateTime.UtcNow; if (SchedulerDTO.SchedulerId == 0) { autoNumberDTO = await _AutoNumber.GetAutoNumber(1, "SCHEDULER", LoginDTO); SchedulerDTO.SchedulerId = autoNumberDTO.StartNumber; SchedulerDTO.SchedulerCreatedById = LoginDTO.UserId; SchedulerDTO.SchedulerCreatedOn = DateTime.UtcNow; await _SchedulerDAL.SaveScheduler(SchedulerDTO, LoginDTO); await ResyncJobsForSchedulerAsync(SchedulerDTO.SchedulerId, LoginDTO); return $"{SuccessResponse.SaveSuccessMessage} {SchedulerDTO.SchedulerId}"; } else { await _SchedulerDAL.UpdateScheduler(SchedulerDTO, LoginDTO); await ResyncJobsForSchedulerAsync(SchedulerDTO.SchedulerId, LoginDTO); return $"{SuccessResponse.UpdateSuccessMessage} {SchedulerDTO.SchedulerId}"; } } catch (ValidationException vex) { throw new ValidationException(vex.Message, vex); } catch (Exception) { if (autoNumberDTO != null && SchedulerDTO.SchedulerId > 0) await _AutoNumber.RollbackAutoNumber("SCHEDULER", SchedulerDTO.SchedulerId, LoginDTO); throw; } } public Task DeleteScheduler(int SchedulerId, LoginDTO LoginDTO) => _SchedulerDAL.DeleteScheduler(SchedulerId, LoginDTO); public Task GetSelectListScheduler(CriteriaDTO CriteriaDTO, LoginDTO LoginDTO) => _SchedulerDAL.GetSelectListScheduler(CriteriaDTO, LoginDTO); } }