using DigitalData.Modules.Database; using EnvelopeGenerator.Service.Schedulers; using Microsoft.Extensions.Options; namespace EnvelopeGenerator.Service; public sealed class Worker : BackgroundService { private readonly ILogger _logger; private readonly ServiceConfig _config; private readonly string _connectionString; private readonly TempFiles _tempFiles; private readonly SchedulerFinishEnvelope _schedulerFinishEnvelope; private readonly SchedulerEnvelopeTaskApi _schedulerEnvelopeTaskApi; public Worker( ILogger logger, IOptions config, IConfiguration configuration, TempFiles tempFiles, SchedulerFinishEnvelope schedulerFinishEnvelope, SchedulerEnvelopeTaskApi schedulerEnvelopeTaskApi) { _logger = logger; _config = config.Value; _connectionString = configuration.GetConnectionString("Default") ?? throw new InvalidOperationException("ConnectionStrings:Default is not configured."); _tempFiles = tempFiles; _schedulerFinishEnvelope = schedulerFinishEnvelope; _schedulerEnvelopeTaskApi = schedulerEnvelopeTaskApi; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { try { _logger.LogInformation("EnvelopeGenerator.Service starting..."); // 1. Validate connection string if (string.IsNullOrWhiteSpace(_connectionString)) throw new InvalidOperationException("Connection string is empty!"); // 2. Build LogConfig (required by CommonServices jobs via JobDataMap) var logConfig = LogConfigFactory.Create(_config); _logger.LogInformation("DEBUG = {Debug}", _config.Debug); // 3. Connect to DB and load GDPicture license _logger.LogDebug("Initializing Database..."); var database = new MSSQLServer(logConfig, _connectionString); if (!database.DBInitialized) throw new InvalidOperationException("Database connection could not be established!"); _logger.LogDebug("Database initialized."); var licenseKey = database.GetScalarValue( "SELECT LICENSE FROM TBDD_3RD_PARTY_MODULES WHERE NAME = 'GDPICTURE' AND ACTIVE = 1") as string; if (string.IsNullOrWhiteSpace(licenseKey)) throw new InvalidOperationException("GDPicture license could not be loaded!"); _logger.LogDebug("GDPicture license loaded."); // 4. Create service-level temp directory _tempFiles.Create(); // 5. Start FinalizeDocument scheduler _logger.LogDebug("Initializing schedulers..."); await _schedulerFinishEnvelope.Start(licenseKey!, logConfig); // 6. Delay between schedulers (legacy behavior preserved) await Task.Delay(2500, stoppingToken); // 7. Start API envelope scheduler await _schedulerEnvelopeTaskApi.Start(logConfig); _logger.LogInformation("EnvelopeGenerator.Service started!"); // 8. Wait for cancellation (service runs until stopped) await Task.Delay(Timeout.Infinite, stoppingToken); } catch (OperationCanceledException) { // Normal shutdown � not an error } catch (Exception ex) { _logger.LogError(ex, "EnvelopeGenerator.Service encountered a fatal error during startup."); throw; } } public override async Task StopAsync(CancellationToken cancellationToken) { _logger.LogInformation("EnvelopeGenerator.Service stopping..."); try { await _schedulerFinishEnvelope.Stop(); await _schedulerEnvelopeTaskApi.Stop(); _tempFiles.CleanUp(); } catch (Exception ex) { _logger.LogError(ex, "Error during service shutdown."); } await base.StopAsync(cancellationToken); _logger.LogInformation("EnvelopeGenerator.Service stopped!"); } }