public static JobStepInstanceResult GetResult(JobStepInstance jobStepInstance) { if (jobStepInstance == null) { return(null); } object _lock = new object(); lock (_lock) { var jobStepResult = new JobStepInstanceResult(); jobStepResult.JobStepId = jobStepInstance.JobStep.Id; jobStepResult.JobInstanceId = jobStepInstance.AssociatedJobInstance.Id; jobStepResult.JobStepInstanceId = jobStepInstance.Id; jobStepResult.OrderIndex = jobStepInstance.OrderIndex; jobStepResult.Status = jobStepInstance.Status; jobStepResult.ActualStartTime = jobStepInstance.ActualStartTime; jobStepResult.ActualEndTime = jobStepInstance.ActualEndTime; jobStepResult.ActualDuration = jobStepInstance.ActualDuration; jobStepResult.HasRecordErrors = jobStepInstance.HasRecordErrors; jobStepResult.HasRuntimeErrors = jobStepInstance.HasRuntimeErrors; jobStepResult.Exceptions = WebServiceException.Convert(jobStepInstance.Exceptions); return(jobStepResult); } }
public void Initialize(Integration integration, JobInstance jobInstance, JobStepInstance previousJobStepInstance, JobStepInstance jobStepInstance, ISyncEngineConfigurator configurator) { Integration = integration; JobInstance = jobInstance; PreviousJobStepInstance = previousJobStepInstance; JobStepInstance = jobStepInstance; Configurator = configurator; }
public void UpdateJobStepStatusInQueueLog(JobStepInstance jobStepInstance) { if (jobStepInstance == null) { throw new Exception("Job step instance can not be null."); } using (var dbContext = new ls.QueueManagementDataContext(_connectionString)) { var queuedJobStepInstance = dbContext.JobStepQueues.Where(d => d.JobStepInstanceId == jobStepInstance.Id).FirstOrDefault(); if (queuedJobStepInstance != null) { queuedJobStepInstance.UpdatedDate = DateTime.Now; queuedJobStepInstance.ActualStartTime = jobStepInstance.ActualStartTime.HasValue ? jobStepInstance.ActualStartTime.Value : new DateTime?(); queuedJobStepInstance.ActualEndTime = jobStepInstance.ActualEndTime.HasValue ? jobStepInstance.ActualEndTime.Value : new DateTime?(); queuedJobStepInstance.JobStepQueueStatusId = (byte)jobStepInstance.Status; dbContext.SubmitChanges(); } } }
/// <summary> /// /// </summary> /// <param name="jobInstanceId"></param> /// <returns>Returns null if a "sync object" no longer exists.</returns> public JobInstance GetJobInstanceFromQueueLog(Guid jobInstanceId, bool throwExceptionIfSyncObjectsAreDeletedOrDisabled = false) { if (!JobQueueManager.IsSafeForQueueLogRetrieval) { throw new Exception("The Job Queue Manager is in an unsafe state as job statuses may change. Queue retrieval from the database is disallowed."); } var configurator = new SyncEngineDatabaseConfigurator(_connectionString); using (var dbContext = new ls.QueueManagementDataContext(_connectionString)) { var jobInstanceInDbQueue = dbContext.JobQueues.Where(d => d.JobInstanceId == jobInstanceId).FirstOrDefault(); var integration = configurator.GetIntegrationByJobId(jobInstanceInDbQueue.JobId); if (integration == null || !integration.IsEnabled) { goto SyncObjectsForJobInstanceHaveChanged; } var job = integration.Jobs.Where(d => d.Id == jobInstanceInDbQueue.JobId).FirstOrDefault(); if (job == null || !job.IsEnabled) { goto SyncObjectsForJobInstanceHaveChanged; } var sourceDataSource = job.SourceDataSources.Values.Where(d => d.Id == jobInstanceInDbQueue.SourceDataSourceId).FirstOrDefault(); if (sourceDataSource == null) { goto SyncObjectsForJobInstanceHaveChanged; } if (job.TargetDataSource.Id != jobInstanceInDbQueue.TargetDataSourceId) { goto SyncObjectsForJobInstanceHaveChanged; } var jobStepInstancesInDbQueue = dbContext.JobStepQueues.Where(d => d.JobInstanceId == jobInstanceInDbQueue.JobInstanceId).ToList(); if (jobStepInstancesInDbQueue.Count == 0) { goto SyncObjectsForJobInstanceHaveChanged; } List <JobStepInstance> jobStepInstanceObjs = new List <JobStepInstance>(); foreach (var jobStepInstanceInDbQueue in jobStepInstancesInDbQueue) { var jobStep = job.Steps.Where(d => d.Id == jobStepInstanceInDbQueue.JobStepId).FirstOrDefault(); if (jobStep == null || !jobStep.IsEnabled) { goto SyncObjectsForJobInstanceHaveChanged; } var jobStepInstanceObj = new JobStepInstance(jobStepInstanceInDbQueue.JobStepInstanceId, jobStep, jobStepInstanceInDbQueue.OrderIndex); jobStepInstanceObj.Status = (JobStepQueueStatus)jobStepInstanceInDbQueue.JobStepQueueStatusId; jobStepInstanceObjs.Add(jobStepInstanceObj); } var filters = JobFilterHelper.ParseFromDatabaseText(jobInstanceInDbQueue.Filters); var invocationSourceType = jobInstanceInDbQueue.IsOnDemand == true ? JobInvocationSourceType.OnDemand : JobInvocationSourceType.Scheduled; var queueRequest = new JobQueueRequest(jobInstanceInDbQueue.QueueRequestId, integration, job, invocationSourceType); var jobInstanceObj = new JobInstance(queueRequest, jobInstanceInDbQueue.JobInstanceId, integration, job, sourceDataSource, job.TargetDataSource, jobStepInstanceObjs, jobInstanceInDbQueue.ScheduledStartTime, jobInstanceInDbQueue.InvocationSource, invocationSourceType, filters.ToList()); queueRequest.JobInstances.Add(jobInstanceObj); jobInstanceObj.Status = (JobQueueStatus)jobInstanceInDbQueue.JobQueueStatusId; return(jobInstanceObj); SyncObjectsForJobInstanceHaveChanged: if (throwExceptionIfSyncObjectsAreDeletedOrDisabled) { throw new Exception(string.Format("Queued job '{0}' in database logger has changed sync objects.", jobInstanceInDbQueue.JobInstanceId)); } else { return(null); } } }
public static void ExecuteStep(JobInstance jobInstance, JobStepInstance previousJobStepInstance, JobStepInstance currentJobStepInstance, ISyncEngineConfigurator configurator) { Type jobStepType = jobInstance.Integration.PackageAssembly.GetType(currentJobStepInstance.JobStep.FullyQualifiedName); if (jobStepType == null) { throw new Exception(string.Format("Job step with fully qualified name '{0}' was not found in assembly '{1}'.", currentJobStepInstance.JobStep.FullyQualifiedName, jobInstance.Integration.PackageAssembly.Location)); } // ensure the step class inherits from the proper base class to ensure the Initialize method is available bool hasCorrectBaseType = false; var baseType = jobStepType.BaseType; while (baseType != typeof(Object)) { if (baseType == typeof(JobStepInvocation)) { hasCorrectBaseType = true; break; } baseType = baseType.BaseType; } if (!hasCorrectBaseType) { throw new Exception(string.Format("Job step class '{0}' must derive from '{1}'.", jobStepType.Name, typeof(JobStepInvocation).FullName)); } var jobStepInvocation = Activator.CreateInstance(jobStepType); if (jobStepInvocation is CustomActionStep) { var jobStepObj = (CustomActionStep)jobStepInvocation; jobStepObj.Initialize(jobInstance.Integration, jobInstance, previousJobStepInstance, currentJobStepInstance, configurator); jobStepObj.Process(); if (previousJobStepInstance != null && ((previousJobStepInstance.HasDeferredExecutionUntilNextStep.HasValue && previousJobStepInstance.HasDeferredExecutionUntilNextStep.Value == true) || (previousJobStepInstance.GetType() is CustomActionStep))) { currentJobStepInstance.SourceJobBatch = previousJobStepInstance.SourceJobBatch; currentJobStepInstance.TargetJobBatch = previousJobStepInstance.TargetJobBatch; currentJobStepInstance.HasDeferredExecutionUntilNextStep = true; } else { currentJobStepInstance.HasDeferredExecutionUntilNextStep = false; } } else if (jobStepInvocation is DataMapStep) { var jobStepObj = (DataMapStep)jobStepInvocation; jobStepObj.Initialize(jobInstance.Integration, jobInstance, previousJobStepInstance, currentJobStepInstance, configurator); var dataMapOutput = jobStepObj.Process(); if (dataMapOutput == null) { throw new Exception("Job step must return a value."); } currentJobStepInstance.HasDeferredExecutionUntilNextStep = dataMapOutput.DeferExecutionUntilNextStep; JobBatch sourceJobBatch = null; JobBatch targetJobBatch = null; EntityBatch sourceEntityBatch = null; EntityBatch targetEntityBatch = null; EntityBatch oneWayEntityBatch = null; IOneWayDataMap oneWayDataMap = null; TwoWayDataMap twoWayDataMap = null; if (dataMapOutput.DataMap is IOneWayDataMap) { oneWayDataMap = (IOneWayDataMap)dataMapOutput.DataMap; if (dataMapOutput.DataMap is OneWayDataMap) { oneWayEntityBatch = OneToOneDataMapProcessor.Compare((OneWayDataMap)dataMapOutput.DataMap, dataMapOutput.SourceData, dataMapOutput.SourceDataDuplicateRowBehavior, dataMapOutput.TargetData, dataMapOutput.TargetDataDuplicateRowBehavior, dataMapOutput.RowsToProcess); } else if (dataMapOutput.DataMap is OneToMany_OneWayDataMap) { if (dataMapOutput.RowsToProcess != null) { throw new Exception("Rows to process Func is not supported for one-to-many data maps."); } oneWayEntityBatch = OneToManyDataMapProcessor.Compare((OneToMany_OneWayDataMap)dataMapOutput.DataMap, dataMapOutput.SourceData, dataMapOutput.SourceDataDuplicateRowBehavior, dataMapOutput.TargetData, dataMapOutput.TargetDataDuplicateRowBehavior); } if (oneWayEntityBatch.EntityDefinition.SyncSide == SyncSide.Source) { oneWayEntityBatch.LoggingBehavior = dataMapOutput.SourceSideLoggingBehavior; } else if (oneWayEntityBatch.EntityDefinition.SyncSide == SyncSide.Target) { oneWayEntityBatch.LoggingBehavior = dataMapOutput.TargetSideLoggingBehavior; } } else if (dataMapOutput.DataMap is TwoWayDataMap) { twoWayDataMap = (TwoWayDataMap)dataMapOutput.DataMap; OneToOneDataMapProcessor.Compare(twoWayDataMap, dataMapOutput.SourceData, dataMapOutput.SourceDataDuplicateRowBehavior, dataMapOutput.TargetData, dataMapOutput.TargetDataDuplicateRowBehavior, dataMapOutput.RowsToProcess, out sourceEntityBatch, out targetEntityBatch); sourceEntityBatch.LoggingBehavior = dataMapOutput.SourceSideLoggingBehavior; targetEntityBatch.LoggingBehavior = dataMapOutput.TargetSideLoggingBehavior; } else { throw new DerivedClassNotImplementedException <OneToOneDataMap>(dataMapOutput.DataMap); } if (previousJobStepInstance != null && previousJobStepInstance.HasDeferredExecutionUntilNextStep.HasValue && previousJobStepInstance.HasDeferredExecutionUntilNextStep.Value == true) { sourceJobBatch = previousJobStepInstance.SourceJobBatch; targetJobBatch = previousJobStepInstance.TargetJobBatch; } else { sourceJobBatch = new JobBatch(SyncSide.Source, jobInstance.SourceDataSource); targetJobBatch = new JobBatch(SyncSide.Target, jobInstance.TargetDataSource); } if (dataMapOutput.DataMap is IOneWayDataMap) { if (oneWayDataMap.SyncDirection == SyncDirection.SourceToTarget) { targetJobBatch.EntityBatches.Add(oneWayEntityBatch); } else if (oneWayDataMap.SyncDirection == SyncDirection.TargetToSource) { sourceJobBatch.EntityBatches.Add(oneWayEntityBatch); } else { throw new EnumValueNotImplementedException <SyncDirection>(oneWayDataMap.SyncDirection); } } else if (dataMapOutput.DataMap is TwoWayDataMap) { sourceJobBatch.EntityBatches.Add(sourceEntityBatch); targetJobBatch.EntityBatches.Add(targetEntityBatch); } else { throw new DerivedClassNotImplementedException <OneToOneDataMap>(dataMapOutput.DataMap); } currentJobStepInstance.SourceJobBatch = sourceJobBatch; currentJobStepInstance.TargetJobBatch = targetJobBatch; if (!currentJobStepInstance.HasDeferredExecutionUntilNextStep.Value) { sourceJobBatch.SubmitToDataSource(); if (sourceJobBatch.HasRecordErrors) { currentJobStepInstance.HasRecordErrors = true; currentJobStepInstance.Exceptions = sourceJobBatch.GetExceptions(); } SyncEngineLogger.WriteToLog(jobInstance, currentJobStepInstance, sourceJobBatch); targetJobBatch.SubmitToDataSource(); if (targetJobBatch.HasRecordErrors) { currentJobStepInstance.HasRecordErrors = true; currentJobStepInstance.Exceptions = targetJobBatch.GetExceptions(); } SyncEngineLogger.WriteToLog(jobInstance, currentJobStepInstance, targetJobBatch); } } else if (jobStepInvocation is EntityBatchStep) { var jobStepObj = (EntityBatchStep)jobStepInvocation; jobStepObj.Initialize(jobInstance.Integration, jobInstance, previousJobStepInstance, currentJobStepInstance, configurator); var entityBatchOutput = jobStepObj.Process(); if (entityBatchOutput == null) { throw new Exception("Job step must return a value."); } currentJobStepInstance.HasDeferredExecutionUntilNextStep = entityBatchOutput.DeferExecutionUntilNextStep; JobBatch sourceJobBatch; JobBatch targetJobBatch; if (previousJobStepInstance != null && previousJobStepInstance.HasDeferredExecutionUntilNextStep.Value == true) { sourceJobBatch = previousJobStepInstance.SourceJobBatch; targetJobBatch = previousJobStepInstance.TargetJobBatch; } else { sourceJobBatch = new JobBatch(SyncSide.Source, jobInstance.SourceDataSource); targetJobBatch = new JobBatch(SyncSide.Target, jobInstance.TargetDataSource); } if (entityBatchOutput.SourceSideEntityBatches != null) { foreach (var sourceSideEntityBatch in entityBatchOutput.SourceSideEntityBatches) { sourceJobBatch.EntityBatches.Add(sourceSideEntityBatch); } } if (entityBatchOutput.TargetSideEntityBatches != null) { foreach (var targetSideEntityBatch in entityBatchOutput.TargetSideEntityBatches) { targetJobBatch.EntityBatches.Add(targetSideEntityBatch); } } currentJobStepInstance.SourceJobBatch = sourceJobBatch; currentJobStepInstance.TargetJobBatch = targetJobBatch; if (!currentJobStepInstance.HasDeferredExecutionUntilNextStep.Value) { sourceJobBatch.SubmitToDataSource(); if (sourceJobBatch.HasRecordErrors) { currentJobStepInstance.HasRecordErrors = true; currentJobStepInstance.Exceptions = sourceJobBatch.GetExceptions(); } SyncEngineLogger.WriteToLog(jobInstance, currentJobStepInstance, sourceJobBatch); targetJobBatch.SubmitToDataSource(); if (targetJobBatch.HasRecordErrors) { currentJobStepInstance.HasRecordErrors = true; currentJobStepInstance.Exceptions = targetJobBatch.GetExceptions(); } SyncEngineLogger.WriteToLog(jobInstance, currentJobStepInstance, targetJobBatch); } } else if (jobStepInvocation is JobBatchStep) { var jobStepObj = (JobBatchStep)jobStepInvocation; jobStepObj.Initialize(jobInstance.Integration, jobInstance, previousJobStepInstance, currentJobStepInstance, configurator); var jobBatchOutput = jobStepObj.Process(); if (jobBatchOutput == null) { throw new Exception("Job step must return a value."); } if (jobBatchOutput.SourceSideJobBatch != null) { jobBatchOutput.SourceSideJobBatch.SubmitToDataSource(); if (jobBatchOutput.SourceSideJobBatch.HasRecordErrors) { currentJobStepInstance.HasRecordErrors = true; currentJobStepInstance.Exceptions = jobBatchOutput.SourceSideJobBatch.GetExceptions(); } SyncEngineLogger.WriteToLog(jobInstance, currentJobStepInstance, jobBatchOutput.SourceSideJobBatch); } else { SyncEngineLogger.WriteToLog(LogEntryType.Info, jobInstance, currentJobStepInstance, jobInstance.SourceDataSource.DataSource, "Job step '{0}' for job '{1}' returned a null job batch for source-side data source '{2}'.", currentJobStepInstance.JobStep.Name, jobInstance.Job.Name, jobInstance.SourceDataSource.DataSource.Name); } if (jobBatchOutput.TargetSideJobBatch != null) { jobBatchOutput.TargetSideJobBatch.SubmitToDataSource(); if (jobBatchOutput.TargetSideJobBatch.HasRecordErrors) { currentJobStepInstance.HasRecordErrors = true; currentJobStepInstance.Exceptions = jobBatchOutput.TargetSideJobBatch.GetExceptions(); } SyncEngineLogger.WriteToLog(jobInstance, currentJobStepInstance, jobBatchOutput.TargetSideJobBatch); } else { SyncEngineLogger.WriteToLog(LogEntryType.Info, jobInstance, currentJobStepInstance, jobInstance.TargetDataSource.DataSource, "Job step '{0}' for job '{1}' returned a null job batch for target-side data source '{2}'.", currentJobStepInstance.JobStep.Name, jobInstance.Job.Name, jobInstance.TargetDataSource.DataSource.Name); } } else { throw new DerivedClassNotImplementedException <JobStepInvocation>(jobStepInvocation); } }
public JobStepQueueStatusChangedArgs(JobInstance associatedJobInstance, JobStepInstance updatedJobStepInstance) { AssociatedJobInstance = associatedJobInstance; UpdatedJobStepInstance = updatedJobStepInstance; }
public static void ExecuteJob(JobInstance jobInstance, ISyncEngineConfigurator configurator) { jobInstance.ActualStartTime = DateTime.Now; if (jobInstance.MaxDelayedStartExceeded) { jobInstance.Status = JobQueueStatus.InProgress_MaxDelayExceeded; } else { jobInstance.Status = JobQueueStatus.InProgress; } bool terminateNextStepsOnStepFailure; bool isSafeJobStopViaException = false; // used to stop job execution without logging an error switch (jobInstance.Job.TerminateOnErrorType) { case JobTerminateOnErrorType.NeverTerminateOnError: case JobTerminateOnErrorType.TerminateExecutingStepOnly: terminateNextStepsOnStepFailure = false; break; case JobTerminateOnErrorType.TerminateExecutingDataSourceOnly: case JobTerminateOnErrorType.TerminateJob: terminateNextStepsOnStepFailure = true; break; default: throw new EnumValueNotImplementedException <JobTerminateOnErrorType>(jobInstance.Job.TerminateOnErrorType); } bool previousJobStepHasRuntimeErrors = false; JobStepInstance previousJobStepInstance = null; foreach (var jobStepInstance in jobInstance.JobStepInstances) { // handle potential job instances that may have been partially executed prior to machine or service restart if (jobStepInstance.Status == JobStepQueueStatus.Completed) { continue; } else if (jobStepInstance.Status == JobStepQueueStatus.Completed_WithError || jobStepInstance.Status == JobStepQueueStatus.DidNotRun_JobError) { previousJobStepHasRuntimeErrors = true; jobInstance.HasRuntimeErrors = true; continue; } else if (isSafeJobStopViaException) { continue; } if (previousJobStepHasRuntimeErrors && terminateNextStepsOnStepFailure) { jobStepInstance.Status = JobStepQueueStatus.DidNotRun_JobError; } else { jobStepInstance.ActualStartTime = DateTime.Now; jobStepInstance.Status = JobStepQueueStatus.InProgress; jobStepInstance.HasRuntimeErrors = false; try { jobInstance.RunningJobStepInstance = jobStepInstance; JobStepInvoker.ExecuteStep(jobInstance, previousJobStepInstance, jobStepInstance, configurator); jobStepInstance.ActualEndTime = DateTime.Now; if (jobStepInstance.HasRecordErrors) { jobInstance.HasRecordErrors = true; } if (jobStepInstance.HasRuntimeErrors) { jobStepInstance.Status = JobStepQueueStatus.Completed_WithError; jobInstance.HasRuntimeErrors = true; previousJobStepHasRuntimeErrors = true; } else { jobStepInstance.Status = JobStepQueueStatus.Completed; } } catch (SafeJobStopException ex) { jobStepInstance.ActualEndTime = DateTime.Now; isSafeJobStopViaException = true; SyncEngineLogger.WriteByParallelTaskContext(LogEntryType.Info, () => { return(string.Format("Job step '{0}' of job '{1}' was terminated safely with message: {2}", jobStepInstance.JobStep.Name, jobStepInstance.AssociatedJobInstance.Job.Name, ex.Message)); }); continue; } catch (Exception ex) { jobStepInstance.ActualEndTime = DateTime.Now; jobStepInstance.HasRuntimeErrors = true; jobStepInstance.Status = JobStepQueueStatus.Completed_WithError; jobInstance.HasRuntimeErrors = true; jobInstance.Exceptions.Add(ex); previousJobStepHasRuntimeErrors = true; SyncEngineLogger.WriteByParallelTaskContext(ex); jobInstance.RunningJobStepInstance = null; continue; } } previousJobStepInstance = jobStepInstance; } jobInstance.ActualEndTime = jobInstance.JobStepInstances.Select(d => d.ActualEndTime).Max(); jobInstance.RunningJobStepInstance = null; if (jobInstance.HasRuntimeErrors && terminateNextStepsOnStepFailure) { jobInstance.Status = JobQueueStatus.Terminated_WithError; } else if (jobInstance.HasRuntimeErrors) { jobInstance.Status = JobQueueStatus.Completed_WithError; } else { jobInstance.Status = JobQueueStatus.Completed; } }
public static List <JobInstance> QueueJob(Integration integration, IEnumerable <DataSource> sourceSideDataSourcesToRun, Job jobToRun, DateTime scheduledStartTime, string invocationSource, JobInvocationSourceType invocationSourceType, List <JobFilter> filters = null) { if (integration == null) { throw new Exception("Integration is missing or empty."); } if (sourceSideDataSourcesToRun == null || sourceSideDataSourcesToRun.Where(d => d != null).Count() == 0) { throw new Exception(string.Format("At least one source-side data source is required to queue job '{0}'.", jobToRun.Name)); } foreach (var dataSource in sourceSideDataSourcesToRun) { if (!jobToRun.SourceDataSources.ContainsKey(dataSource.Name)) { throw new Exception(string.Format("Source-side data source '{0}' does not exist for job '{1}'. This job will not be queued for execution.", dataSource.Name, jobToRun.Name)); } } if (String.IsNullOrWhiteSpace(invocationSource)) { throw new Exception("Invocation source is missing or empty."); } if (!integration.IsEnabled) { throw new Exception(string.Format("Job '{0}' could not be queued for execution because integration '{1}' is disabled.", jobToRun.Name, integration.Name)); } if (!jobToRun.IsEnabled) { throw new Exception(string.Format("Job '{0}' could not be queued for execution because it is disabled.", jobToRun.Name)); } if (jobToRun.Steps.Where(d => d.IsEnabled).Count() == 0) { throw new Exception(string.Format("Job '{0}' could not be queued for execution because no job steps exist or all are disabled.", jobToRun.Name)); } SetMaxConcurrentThreadsForIntegration(integration); List <JobInstance> queuedJobs = new List <JobInstance>(); JobInstance jobInstance; JobStepInstance jobStepInstance; List <JobStepInstance> jobStepInstances; var queueRequest = new JobQueueRequest(integration, jobToRun, invocationSourceType); queueRequest.StatusChanged += new EventHandler <JobQueueRequestStatusChangedArgs>(HandleChangedQueueRequestStatus); queueRequest.Status = JobQueueRequestStatus.Waiting; foreach (var sourceSideDataSource in sourceSideDataSourcesToRun) { byte jobStepIdx = 0; jobStepInstances = new List <JobStepInstance>(); foreach (var jobStep in jobToRun.Steps) { if (jobStep.IsEnabled) { jobStepInstance = new JobStepInstance(jobStep, jobStepIdx); jobStepInstance.StatusChanged += new EventHandler <JobStepQueueStatusChangedArgs>(HandleChangedJobStepStatus); jobStepInstances.Add(jobStepInstance); //jobStepInstance.Status = JobStepQueueStatus.Waiting; jobStepIdx++; } } jobInstance = new JobInstance(queueRequest, integration, jobToRun, sourceSideDataSource, jobToRun.TargetDataSource, jobStepInstances, scheduledStartTime, invocationSource, invocationSourceType, filters); queueRequest.JobInstances.Add(jobInstance); // change the status here to avoid the job step not having an association with the job instance when status changes are logged foreach (var jobStepInstanceToFireStatusChangeFor in jobStepInstances) { jobStepInstanceToFireStatusChangeFor.Status = JobStepQueueStatus.Waiting; } jobInstance.StatusChanged += new EventHandler <JobQueueStatusChangedArgs>(HandleChangedJobStatus); if (waitingJobsByIntegrationId.ContainsKey(jobInstance.Integration.Id)) { waitingJobsByIntegrationId[jobInstance.Integration.Id].Add(jobInstance); } else { waitingJobsByIntegrationId.Add(jobInstance.Integration.Id, new List <JobInstance>() { jobInstance }); } // cache the job instance in memory if on-demand (temporary to get around OutOfMemoryException) if (jobInstance.InvocationSourceType == JobInvocationSourceType.OnDemand) { jobInstancesById.Add(jobInstance.Id, jobInstance); queueRequestsById.Add(queueRequest.Id, queueRequest); } jobInstance.Status = JobQueueStatus.Scheduled; queuedJobs.Add(jobInstance); if (JobQueued != null) { JobQueued(null, new JobQueuedArgs(jobInstance)); } } return(queuedJobs); }