private static async Task CreateDbTargets(AzureSqlJobClient elasticJobs, CustomCollectionTargetInfo rootTarget, BackgroundTaskService.BackgroundTaskLog log
                                                  , IList <DatabaseTarget> dbTargets, int pageSize, int delay)
        {
            for (int i = 0; i < dbTargets.Count; i += pageSize)
            {
                await Task.WhenAll(dbTargets.Skip(i).Take(pageSize).Select(x => CreateDbTarget(elasticJobs, rootTarget, log, x)).ToArray());

                Thread.Sleep(delay);
            }
        }
        private static async Task <int> FindLastUsedNumber(AzureSqlJobClient elasticJobs, string jobNamePrefix, BackgroundTaskService.BackgroundTaskLog log)
        {
            for (int i = 0; i < int.MaxValue; i++)
            {
                var jobName = BuildJobName(jobNamePrefix, i);
                log.LogInfo($"checking if {jobName} exists");
                var job = await elasticJobs.Jobs.GetJobAsync(jobName);

                if (job == null)
                {
                    return(i - 1);
                }
            }
            throw new Exception($"we used {int.MaxValue} numbers for jobs ????");
        }
        private static async Task <bool> IsJobInProgress(AzureSqlJobClient elasticJobs, string lastJobName)
        {
            var executions = await elasticJobs.JobExecutions.ListJobExecutionsAsync(new JobExecutionFilter()
            {
                JobName = lastJobName
            });

            if (executions != null)
            {
                return(executions.Any(jobExecutionInfo =>
                                      jobExecutionInfo.Lifecycle == JobExecutionLifecycle.Created ||
                                      jobExecutionInfo.Lifecycle == JobExecutionLifecycle.InProgress ||
                                      jobExecutionInfo.Lifecycle == JobExecutionLifecycle.WaitingForChildJobExecutions ||
                                      jobExecutionInfo.Lifecycle == JobExecutionLifecycle.WaitingToRetry));
            }
            return(false);
        }
        private static async Task <JobExecutionInfo> StartJob(AzureSqlJobClient elasticJobs, IList <DatabaseTarget> targets
                                                              , BackgroundTaskService.BackgroundTaskLog log, string dacPacName, string dacPacUri)
        {
            var dacPackDef = await elasticJobs.Content.GetContentAsync(dacPacName) ??
                             await elasticJobs.Content.CreateDacpacAsync(dacPacName, new Uri(dacPacUri));

            var pwd        = CreatePassword(Settings.ChalkableSchoolDbPassword);
            var credential = await elasticJobs.Credentials.CreateCredentialAsync(Guid.NewGuid().ToString(), Settings.ChalkableSchoolDbUser, pwd);

            string jobNamePrefix = "Apply DACPAC " + dacPacName + " ";
            int    lastNumber    = await FindLastUsedNumber(elasticJobs, jobNamePrefix, log);

            if (lastNumber >= 0)
            {
                bool inProgress = await IsJobInProgress(elasticJobs, BuildJobName(jobNamePrefix, lastNumber));

                if (inProgress)
                {
                    throw new Exception("Previous job on this version is not end yet");
                }
            }

            var rooTarget = await elasticJobs.Targets.CreateCustomCollectionTargetAsync("Targets for DACPAC " + dacPacName + " " + Guid.NewGuid());

            log.LogInfo("Job targets created as " + rooTarget.TargetId + " " + rooTarget.CustomCollectionName);
            await CreateDbTargets(elasticJobs, rooTarget, log, targets, 20, 2000);

            var jobName = BuildJobName(jobNamePrefix, lastNumber + 1);
            var job     = await elasticJobs.Jobs.CreateJobAsync(jobName, new JobBuilder
            {
                ContentName    = dacPackDef.ContentName,
                TargetId       = rooTarget.TargetId,
                CredentialName = credential.CredentialName
            });

            log.LogInfo("Job created as " + job.TargetId + " " + job.JobName);
            var jobExecution = await elasticJobs.JobExecutions.StartJobExecutionAsync(job.JobName);

            log.LogInfo($"{dacPacName} execution job as {jobExecution.JobExecutionId} with lifecycle {jobExecution.Lifecycle}");
            return(jobExecution);
        }
        private static async Task CreateDbTarget(AzureSqlJobClient elasticJobs, CustomCollectionTargetInfo rootTarget
                                                 , BackgroundTaskService.BackgroundTaskLog log, DatabaseTarget dbTarget)
        {
            try
            {
                var dbTargetInfo = await elasticJobs.Targets.GetDatabaseTargetAsync(dbTarget.Server, dbTarget.Name)
                                   ?? await elasticJobs.Targets.CreateDatabaseTargetAsync(dbTarget.Server, dbTarget.Name);

                var result = await elasticJobs.Targets.AddChildTargetAsync(rootTarget.TargetId, dbTargetInfo.TargetId);

                if (!result)
                {
                    throw new Exception("child target adding returns false");
                }
                log.LogInfo("Targeting db " + dbTarget.Name + "@" + dbTarget.Server + " complete as " + dbTargetInfo.TargetId);
            }
            catch (Exception e)
            {
                log.LogException(e);
                throw new Exception("Targeting db " + dbTarget.Name + "@" + dbTarget.Server + " failed.", e);
            }
        }