using AutomationBLL.Schedule; using Dapr; using GB5Shared.DTO.Framework.Login; using Microsoft.AspNetCore.Mvc; namespace AutomationSL.Subscriptions; // Triggered when JobEngine's QuartzJobExecutor fires a scheduled job whose DaprPubSubTopic was set // by IJobEngineScheduleClient.SyncAsync. This is the "internal dispatch endpoint" referred to in // the Phase 2 plan — resolves which TSCRIPTTARGET the firing JobId belongs to, then applies the // holiday-skip/dependency-chain checks in ScheduledDispatchBLL before enqueuing a run. // // Unverified end-to-end: JobEngineModule is currently deferred/disabled in every host // (ConnectionStrings:QuartzStore not provisioned), so this subscriber has no live publisher to // receive from yet — see JobEngineScheduleClient.cs for the corresponding caveat. [ApiController] public class ScheduledDispatchSubscriber : ControllerBase { private readonly IScheduledDispatchBLL _dispatchBll; private readonly IScheduleBLL _scheduleBll; private readonly ILogger _logger; public ScheduledDispatchSubscriber(IScheduledDispatchBLL dispatchBll, IScheduleBLL scheduleBll, ILogger logger) { _dispatchBll = dispatchBll; _scheduleBll = scheduleBll; _logger = logger; } public record ScheduledDispatchEvent(int JobId, int TenantId, string CorrelationId); [Topic("pubsub", JobEngineScheduleClient.DispatchTopic)] [HttpPost("/Automation/Subscriptions/ScheduledDispatch")] public async Task HandleScheduledDispatchAsync( [FromBody] ScheduledDispatchEvent evt, CancellationToken ct) { _logger.LogInformation( "Scheduled dispatch event received for JobId {JobId} TenantId {TenantId} CorrelationId {CorrelationId}", evt.JobId, evt.TenantId, evt.CorrelationId); try { var login = new LoginDTO { ClientId = evt.TenantId, UserId = 0 }; var schedule = await _scheduleBll.GetByJobEngineJobId(evt.JobId, login, ct).ConfigureAwait(false) ?? throw new InvalidOperationException($"No TSCHEDULE row found for JobEngine JobId {evt.JobId}."); var result = await _dispatchBll.DispatchScheduledRun(schedule.TargetId, login, ct).ConfigureAwait(false); _logger.LogInformation("Scheduled dispatch for TargetId {TargetId} result: {Result}", schedule.TargetId, result); return Ok(new { TargetId = schedule.TargetId, Result = result }); } catch (Exception ex) { _logger.LogError(ex, "Failed to process scheduled dispatch for JobId {JobId}", evt.JobId); return StatusCode(500, ex.Message); } } }