/// <summary> /// Initializes a new instance of the PersistedJobRun class. /// </summary> /// <param name="run">The <see cref="JobRun"/> being persisted.</param> public PersistedJobRun(JobRun run) { if (run == null) { throw new ArgumentNullException("run", "run cannot be null."); } this.ExecutionException = run.ExecutionException; this.FinishDate = run.FinishDate; this.JobId = run.JobId; this.JobType = run.Job != null ? run.Job.GetType().AssemblyQualifiedName : null; this.JobXml = run.Job != null ? run.Job.Serialize() : null; this.ScheduleName = run.ScheduleName; this.StartDate = run.StartDate; }
/// <summary> /// Performs the concrete finishing of the given job run. /// </summary> /// <param name="run">A job run to finish.</param> /// <param name="record">The run's related record.</param> /// <param name="trans">The transaction to access the job store in.</param> private void FinishJobRun(JobRun run, JobRecord record, IJobStoreTransaction trans) { record.FinishDate = run.FinishDate; if (run.ExecutionException != null) { record.Exception = new ExceptionXElement(run.ExecutionException).ToString(); record.Status = JobStatus.Failed; this.RaiseEvent(this.Error, new JobErrorEventArgs(record, run.ExecutionException)); this.EnqueueJobForRetry(run.Job, trans); } else if (run.WasRecovered) { record.Status = JobStatus.Interrupted; } else { record.Status = JobStatus.Succeeded; } if (this.DeleteRecordsOnSuccess) { this.store.DeleteJob(record.Id.Value, trans); } else { this.store.SaveJob(record, trans); } this.runs.Remove(record.Id.Value); this.RaiseEvent(this.FinishJob, new JobRecordEventArgs(record)); }
/// <summary> /// Executes any scheduled jobs that are due. /// </summary> private void ExecuteScheduledJobs() { int count = this.MaximumConcurrency - this.ExecutingJobCount; if (count > 0) { DateTime now = DateTime.UtcNow; long heartbeat = this.lastScheduleCheck == null ? this.Heartbeat : (long)Math.Ceiling(now.Subtract(this.lastScheduleCheck.Value).TotalMilliseconds); this.lastScheduleCheck = now; var scheduleNames = this.Schedules.Select(s => s.Name); var tuples = ScheduledJobTuple.GetExecutableTuples(this.ScheduledJobs, now, heartbeat, count); using (IJobStoreTransaction trans = this.store.BeginTransaction()) { try { foreach (ScheduledJobTuple tuple in tuples) { JobRecord record = ScheduledJob.CreateRecord(tuple.Schedule, tuple.ScheduledJob, now); bool running = this.runs.GetAll().Any( r => tuple.Schedule.Name.Equals(r.ScheduleName, StringComparison.OrdinalIgnoreCase) && tuple.ScheduledJob.JobType.StartsWith(record.JobType, StringComparison.OrdinalIgnoreCase)); if (!running) { IJob job = null; Exception toJobEx = null; try { job = ScheduledJob.CreateFromConfiguration(tuple.ScheduledJob); } catch (ConfigurationErrorsException ex) { toJobEx = ex; this.RaiseEvent(this.Error, new JobErrorEventArgs(record, toJobEx)); } if (job != null) { record.Name = job.Name; record.JobType = JobRecord.JobTypeString(job); record.Data = job.Serialize(); this.store.SaveJob(record, trans); JobRun run = new JobRun(record.Id.Value, job); run.Finished += new EventHandler<JobRunEventArgs>(this.JobRunFinished); this.runs.Add(run); run.Start(); this.RaiseEvent(this.ExecuteScheduledJob, new JobRecordEventArgs(record)); } else { record.Status = JobStatus.FailedToLoadType; record.FinishDate = now; record.Exception = new ExceptionXElement(toJobEx).ToString(); } this.store.SaveJob(record, trans); } } this.runs.Flush(); trans.Commit(); } catch { trans.Rollback(); throw; } } } }
/// <summary> /// Dequeues pending jobs in the job store. /// </summary> private void DequeueJobs() { int count = this.MaximumConcurrency - this.ExecutingJobCount; if (count > 0) { DateTime now = DateTime.UtcNow; using (IJobStoreTransaction trans = this.store.BeginTransaction()) { try { foreach (var record in this.store.GetJobs(JobStatus.Queued, count, now, trans)) { record.Status = JobStatus.Started; record.StartDate = now; IJob job = null; Exception toJobEx = null; try { job = record.ToJob(); } catch (InvalidOperationException ex) { toJobEx = ex.InnerException ?? ex; this.RaiseEvent(this.Error, new JobErrorEventArgs(record, toJobEx)); } if (job != null) { JobRun run = new JobRun(record.Id.Value, job); run.Finished += new EventHandler<JobRunEventArgs>(this.JobRunFinished); this.runs.Add(run); run.Start(); } else { record.Status = JobStatus.FailedToLoadType; record.FinishDate = now; record.Exception = new ExceptionXElement(toJobEx).ToString(); } this.store.SaveJob(record, trans); this.RaiseEvent(this.DequeueJob, new JobRecordEventArgs(record)); } this.runs.Flush(); trans.Commit(); } catch { trans.Rollback(); throw; } } } }
/// <summary> /// Adds a job run to this instance. /// </summary> /// <param name="jobRun">The job run to add.</param> public void Add(JobRun jobRun) { lock (this.runs) { this.runs.Add(jobRun); } }