public bool UpdateJob(JobData job) { using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.Serializable })) { using (Linq2SqlJobStoreDalDataContext context = new Linq2SqlJobStoreDalDataContext(connectionString)) { //If the record we're trying to update is locked (some other thread or service is writing to it), this will return false. var storedJob = context.ExecuteQuery <BackgroundWorkerJob>("SELECT TOP 1 * FROM BackgroundWorkerJobs WITH (ROWLOCK, XLOCK) WHERE Id = {0}", job.Id).FirstOrDefault(); if (storedJob != null) { storedJob.AbsoluteTimeout = job.AbsoluteTimeout; storedJob.CreatedDate = job.CreatedDate; storedJob.Data = job.Data; storedJob.Instance = job.Instance; storedJob.LastErrorMessage = job.LastErrorMessage; storedJob.LastExecutionEndDateTime = job.LastEndTime; storedJob.LastExecutionStartDateTime = job.LastStartTime; storedJob.MetaData = job.MetaData; storedJob.QueueId = job.QueueId; storedJob.StatusId = (int)job.Status; storedJob.Application = job.Application; storedJob.Group = job.Group; storedJob.SuppressHistory = job.SuppressHistory; storedJob.DeleteWhenDone = job.DeleteWhenDone; storedJob.UniqueId = job.UniqueId; storedJob.NextExecutionStartDateTime = job.NextStartTime; storedJob.Name = job.Name; storedJob.Description = job.Description; if (job.Schedule != null) { storedJob.ScheduleType = job.Schedule.GetType().AssemblyQualifiedName; //This bit is a temporary hack. Will change later to move this out of jobstore. string newSchedule = Utils.SerializeObject(job.Schedule, job.Schedule.GetType()); if (newSchedule != storedJob.Schedule) { storedJob.NextExecutionStartDateTime = job.Schedule.GetNextOccurrence(storedJob.LastExecutionStartDateTime.HasValue ? storedJob.LastExecutionStartDateTime.Value : DateTime.Now); } storedJob.Schedule = newSchedule; } else { storedJob.ScheduleType = null; storedJob.Schedule = null; storedJob.NextExecutionStartDateTime = null; } try { context.SubmitChanges(System.Data.Linq.ConflictMode.FailOnFirstConflict); ts.Complete(); return(true); } catch (Exception ex) { logger.Error(string.Format("Failed to submit changes to the database."), ex); } return(false); } } } return(false); }
/// <summary> /// Gets a list of jobs with the specified filter criteria. The nullable filters are only used if non-null values specified. /// </summary> /// <param name="skip">How many records to skip.</param> /// <param name="take">How many records to take.</param> /// <param name="jobIds">The job ids.</param> /// <param name="jobStatuses">The job statuses.</param> /// <param name="queueIds">The queue ids.</param> /// <param name="typeNames">The type names.</param> /// <param name="applications">The applications.</param> /// <param name="groups">The groups.</param> /// <returns></returns> public ReadOnlyCollection <JobData> GetJobs(uint skip = 0, uint take = 1, long[] jobIds = null, JobStatus[] jobStatuses = null, byte[] queueIds = null, string[] typeNames = null, string[] applications = null, string[] groups = null) { using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.Serializable })) { using (Linq2SqlJobStoreDalDataContext context = new Linq2SqlJobStoreDalDataContext(connectionString)) { try { //In order to get a table lock, we have to resort to SQL context.ExecuteQuery <BackgroundWorkerJob>("SELECT TOP 1 * FROM BackgroundWorkerJobs WITH (TABLOCKX)"); var query = context.BackgroundWorkerJobs.OrderBy(j => j.CreatedDate).AsQueryable(); if (jobIds != null && jobIds.Length > 0) { query = query.Where(j => jobIds.Contains(j.Id)); } if (jobStatuses != null && jobStatuses.Length > 0) { query = query.Where(j => jobStatuses.Contains((JobStatus)j.StatusId)); } if (queueIds != null && queueIds.Length > 0) { query = query.Where(j => queueIds.Select(q => (int)q).Contains(j.QueueId)); } if (typeNames != null && typeNames.Length > 0) { query = query.Where(j => typeNames.Contains(j.Type)); } if (applications != null && applications.Length > 0) { query = query.Where(j => applications.Contains(j.Application)); } if (groups != null && groups.Length > 0) { query = query.Where(j => groups.Contains(j.Group)); } List <JobData> jobs = new List <JobData>(); var storedJobs = query.Skip((int)skip).Take((int)take).ToList(); foreach (var storedJob in storedJobs) { Type jobType = Type.GetType(storedJob.Type); if (jobType != null) { var jobData = GetJobData(storedJob); jobs.Add(jobData); } else { storedJob.StatusId = (int)JobStatus.Deleted; storedJob.LastErrorMessage = string.Format("Could not load type '{0}.'", storedJob.Type); } } context.SubmitChanges(); return(jobs.AsReadOnly()); } catch (Exception ex) { logger.LogException(string.Format("Failed to get jobs from the database."), ex); } finally { ts.Complete(); } } } return(null); }