using System.Net.Http.Json; using System.Text.Json; using GB5Shared.DTO.Framework.Login; using GB5Shared.Telemetry; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Newtonsoft.Json; namespace AutomationBLL.Schedule; public class JobEngineScheduleClient : IJobEngineScheduleClient { // Topic JobEngine's QuartzJobExecutor publishes to on fire — see // AutomationSL/Subscriptions/ScheduledDispatchSubscriber.cs for the consumer side. public const string DispatchTopic = "automation.scheduled.dispatch"; private readonly IHttpClientFactory _httpFactory; private readonly IConfiguration _configuration; private readonly ILogger _logger; public JobEngineScheduleClient(IHttpClientFactory httpFactory, IConfiguration configuration, ILogger logger) { _httpFactory = httpFactory; _configuration = configuration; _logger = logger; } public async Task SyncAsync(int targetId, string jobName, string cronExpression, LoginDTO login, CancellationToken ct) { try { var baseUrl = _configuration["JobEngine:BaseUrl"] ?? "http://localhost:5112"; var http = _httpFactory.CreateClient("jobengine"); // JobDefineDTO shape (JobEngineDAL.DTOs.JobDefineDTO) — posted as an anonymous object // rather than a shared type, so Automation carries no compile-time dependency on JobEngine. var payload = new { JobId = 0, JobName = jobName, TenantId = login.ClientId, Status = 1, SchedulerType = "CRON", CronExpression = cronExpression, SourceModule = "Automation", SourceObjectId = targetId, DaprPubSubTopic = DispatchTopic, IsConcurrent = false }; using var request = new HttpRequestMessage(HttpMethod.Post, $"{baseUrl}/JobEngine/SaveJob") { Content = JsonContent.Create(payload) }; request.Headers.Add("Login", JsonConvert.SerializeObject(login)); using var response = await http.SendAsync(request, ct).ConfigureAwait(false); response.EnsureSuccessStatusCode(); var body = await response.Content.ReadFromJsonAsync(cancellationToken: ct).ConfigureAwait(false); if (body.TryGetProperty("Body", out var bodyProp) && bodyProp.TryGetProperty("JobId", out var jobIdProp)) return jobIdProp.GetInt32(); GB5Trace.Step("jobengine-sync-response-unrecognized", new { targetId }); return null; } catch (Exception ex) { // Non-fatal by design — the caller must still persist TSCHEDULE locally. JobEngine is // deferred/disabled in every host today, so this is expected to fail until provisioned. GB5Trace.RecordError(ex, "jobengine-sync-failed"); _logger.LogWarning(ex, "JobEngine sync failed for TargetId {TargetId} — schedule saved locally only", targetId); return null; } } }