protected override async Task ExecuteAsync(CancellationToken stoppingToken) { if (!_autoDeployConfiguration.Enabled) { return; } await Task.Delay(TimeSpan.FromSeconds(_autoDeployConfiguration.StartupDelayInSeconds), stoppingToken); while (!stoppingToken.IsCancellationRequested) { ImmutableArray <DeploymentTarget> deploymentTargets; using (var targetsTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(_autoDeployConfiguration.DefaultTimeoutInSeconds))) { using (CancellationTokenSource linked = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken, targetsTokenSource.Token)) { deploymentTargets = (await _deploymentTargetReadService.GetDeploymentTargetsAsync(linked.Token)) .Where(target => target.Enabled && target.AutoDeployEnabled) .ToImmutableArray(); } } if (deploymentTargets.IsDefaultOrEmpty) { _logger.Verbose("Found no deployment targets with auto deployment enabled, waiting {DelayInSeconds} seconds", _autoDeployConfiguration.EmptyTargetsDelayInSeconds); await Task.Delay(TimeSpan.FromSeconds(_autoDeployConfiguration.EmptyTargetsDelayInSeconds), stoppingToken); continue; } ImmutableArray <DeploymentTarget> targetsWithUrl = deploymentTargets.Where(target => target.Url.HasValue()).ToImmutableArray(); if (targetsWithUrl.IsDefaultOrEmpty) { _logger.Verbose("Found no deployment targets with auto deployment enabled and URL defined, waiting {DelayInSeconds} seconds", _autoDeployConfiguration.EmptyTargetsDelayInSeconds); await Task.Delay(TimeSpan.FromSeconds(_autoDeployConfiguration.EmptyTargetsDelayInSeconds), stoppingToken); continue; } AppVersion[] appVersions; using (var cancellationTokenSource = new CancellationTokenSource( TimeSpan.FromSeconds(_autoDeployConfiguration.MetadataTimeoutInSeconds))) { using (CancellationTokenSource linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationTokenSource.Token, stoppingToken)) { CancellationToken cancellationToken = linkedCancellationTokenSource.Token; IEnumerable <Task <AppVersion> > tasks = targetsWithUrl.Select(target => _monitoringService.GetAppMetadataAsync(target, cancellationToken)); appVersions = await Task.WhenAll(tasks); } } foreach (DeploymentTarget deploymentTarget in targetsWithUrl) { AppVersion appVersion = appVersions.SingleOrDefault(v => v.Target.Id.Equals(deploymentTarget.Id, StringComparison.OrdinalIgnoreCase)); if (appVersion?.SemanticVersion is null || appVersion.PackageId.IsNullOrWhiteSpace()) { continue; } ImmutableHashSet <PackageVersion> packageVersions; using (var packageVersionCancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(_autoDeployConfiguration.DefaultTimeoutInSeconds))) { using (CancellationTokenSource linked = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken, packageVersionCancellationTokenSource.Token)) { packageVersions = (await _packageService.GetPackageVersionsAsync(deploymentTarget.PackageId, cancellationToken: linked.Token, logger: _logger)).ToImmutableHashSet(); } } if (packageVersions.IsEmpty) { continue; } ImmutableHashSet <PackageVersion> filteredPackages = !deploymentTarget.AllowPreRelease ? packageVersions.Where(p => !p.Version.IsPrerelease).ToImmutableHashSet() : packageVersions; if (filteredPackages.IsEmpty) { continue; } ImmutableHashSet <PackageVersion> newerPackages = filteredPackages .Where(package => package.PackageId.Equals(appVersion.PackageId, StringComparison.OrdinalIgnoreCase) && package.Version > appVersion.SemanticVersion) .ToImmutableHashSet(); PackageVersion packageToDeploy = newerPackages .OrderByDescending(package => package.Version) .FirstOrDefault(); if (packageToDeploy != null) { var task = new DeploymentTask(packageToDeploy, deploymentTarget.Id, Guid.NewGuid()); _logger.Information("Auto-deploying package {Package} to target {TargetId}", packageToDeploy, deploymentTarget.Id); _deploymentWorker.Enqueue(task); } } await Task.Delay(TimeSpan.FromSeconds(_autoDeployConfiguration.AfterDeployDelayInSeconds), stoppingToken); } }