public JobExecutionHistory CreateJobExecutionHistory(JobData job) { BackgroundWorkerJobExecutionHistory history = new BackgroundWorkerJobExecutionHistory { AbsoluteTimeout = job.AbsoluteTimeout, CreatedDate = job.CreatedDate, Instance = job.Instance, JobUniqueId = job.UniqueId, Data = job.Data, EndDateTime = job.LastEndTime, ErrorMessage = job.LastErrorMessage, JobId = job.Id, MetaData = job.MetaData, QueueId = job.QueueId, StartDateTime = job.LastStartTime ?? DateTime.Now, StatusId = (int)job.Status, Success = job.Status == JobStatus.Done, Type = job.JobType.AssemblyQualifiedName, Application = job.Application, Group = job.Group, Name = job.Name, Description = job.Description, }; using (Linq2SqlJobStoreDalDataContext context = new Linq2SqlJobStoreDalDataContext(connectionString)) { context.BackgroundWorkerJobExecutionHistories.InsertOnSubmit(history); try { context.SubmitChanges(System.Data.Linq.ConflictMode.FailOnFirstConflict); return(new JobExecutionHistory { AbsoluteTimeout = history.AbsoluteTimeout, Application = history.Application, CreatedDate = history.CreatedDate, Data = history.Data, Description = history.Description, EndTime = history.EndDateTime, ErrorMessage = history.ErrorMessage, Group = history.Group, Id = history.Id, Instance = history.Instance, JobId = history.JobId, JobType = Type.GetType(history.Type), JobUniqueId = history.JobUniqueId, MetaData = history.MetaData, Name = history.Name, QueueId = history.QueueId, StartTime = history.StartDateTime, Status = (JobStatus)history.StatusId, Success = history.Success ?? false, }); } catch (Exception ex) { logger.Error(string.Format("Failed to submit changes to the database."), ex); } } return(null); }
public void DequeueJob(JobData job) { using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.Serializable, Timeout = transactionTimeout })) { using (Linq2SqlJobStoreDalDataContext context = new Linq2SqlJobStoreDalDataContext(connectionString)) { try { //In order to get a table lock, we have to resort to SQL var storedJob = context.ExecuteQuery <BackgroundWorkerJob>("SELECT TOP 1 * FROM BackgroundWorkerJobs WITH (ROWLOCK, XLOCK) WHERE Id = {0}", job.Id).FirstOrDefault(); if (storedJob != null && (storedJob.StatusId == (int)JobStatus.Queuing || storedJob.StatusId == (int)JobStatus.Queued)) { storedJob.StatusId = (int)JobStatus.Ready; storedJob.Instance = null; context.SubmitChanges(System.Data.Linq.ConflictMode.FailOnFirstConflict); ts.Complete(); return; } } catch (Exception ex) { logger.Error("DequeueJob failed.", ex); } } } }
public bool DeleteJob(long jobId, bool deleteHistory = false) { using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.Serializable, Timeout = transactionTimeout })) { using (Linq2SqlJobStoreDalDataContext context = new Linq2SqlJobStoreDalDataContext(connectionString)) { var job = context.BackgroundWorkerJobs.FirstOrDefault(j => j.Id == jobId); if (job != null) { if (deleteHistory) { context.BackgroundWorkerJobExecutionHistories.DeleteAllOnSubmit(context.BackgroundWorkerJobExecutionHistories.Where(jh => jh.JobId == jobId)); } context.BackgroundWorkerJobs.DeleteOnSubmit(job); try { context.SubmitChanges(System.Data.Linq.ConflictMode.FailOnFirstConflict); ts.Complete(); return(true); } catch (Exception ex) { logger.Error(string.Format("Failed to delete job '{0}'.", jobId), ex); } } } } return(false); }
public Alert CreateAlert(long jobId, long?jobHistoryId, string message) { using (Linq2SqlJobStoreDalDataContext context = new Linq2SqlJobStoreDalDataContext(connectionString)) { try { BackgroundWorkerAlert alert = new BackgroundWorkerAlert { JobId = jobId, JobHistoryId = jobHistoryId, Message = message }; context.BackgroundWorkerAlerts.InsertOnSubmit(alert); context.SubmitChanges(); return(new Alert { Id = alert.Id, JobId = alert.JobId, JobHistoryId = alert.JobHistoryId, Message = alert.Message, }); } catch (Exception ex) { logger.Error("CreateAlert failed.", ex); } } return(null); }
public bool DeleteAlerts(long[] ids = null) { using (Linq2SqlJobStoreDalDataContext context = new Linq2SqlJobStoreDalDataContext(connectionString)) { try { var storedAlertsQuery = context.BackgroundWorkerAlerts.AsQueryable(); if (ids != null) { storedAlertsQuery = storedAlertsQuery.Where(a => ids.Contains(a.Id)); } var storedAlerts = storedAlertsQuery.ToList(); if (storedAlerts != null && storedAlerts.Count > 0) { context.BackgroundWorkerAlerts.DeleteAllOnSubmit(storedAlerts); context.SubmitChanges(ConflictMode.FailOnFirstConflict); } return(true); } catch (Exception ex) { logger.Error("DeleteAlerts failed.", ex); } } return(false); }
/// <summary> /// Schedules (create with schedule) the job in the job store. /// </summary> /// <param name="jobType">Type of the job.</param> /// <param name="data">The data.</param> /// <param name="metaData">The meta data.</param> /// <param name="queueId">The queue id.</param> /// <param name="schedule">The schedule.</param> /// <param name="name">The name.</param> /// <param name="description">The description.</param> /// <param name="application">The application.</param> /// <param name="group">The group.</param> /// <param name="absoluteTimeout">The absolute timeout.</param> /// <param name="jobStatus">The job status.</param> /// <param name="createdDate">The created date. Jobs are ordered by creation date for execution so it's possible to prioritize jobs for queueing.</param> /// <param name="suppressHistory">if set to <c>true</c> no execution history records are created.</param> /// <param name="deleteWhenDone">if set to <c>true</c> the job is deleted after a successfull (status Done) execution.</param> /// <returns></returns> public JobData ScheduleJob(Type jobType, string data, string metaData, byte queueId, ISchedule schedule, string name = null, string description = null, string application = null, string group = null, TimeSpan?absoluteTimeout = null, JobStatus?jobStatus = JobStatus.Ready, DateTime?createdDate = null, bool suppressHistory = false, bool deleteWhenDone = false) { if (jobType == null) { throw new ArgumentException("jobType cannot be null."); } BackgroundWorkerJob newJob = new BackgroundWorkerJob { AbsoluteTimeout = absoluteTimeout, CreatedDate = DateTime.Now, Data = data, MetaData = metaData, QueueId = queueId, StatusId = (int?)jobStatus ?? (int)JobStatus.Ready, Type = jobType.AssemblyQualifiedName, ScheduleType = schedule.GetType().AssemblyQualifiedName, Schedule = Utils.SerializeObject(schedule, schedule.GetType()), Instance = null, //This is just a default to show that no instance has picked this up Application = application, Group = group, Name = name, Description = description, SuppressHistory = suppressHistory, DeleteWhenDone = deleteWhenDone, }; using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.Serializable })) { using (Linq2SqlJobStoreDalDataContext context = new Linq2SqlJobStoreDalDataContext(connectionString)) { //In order to get a table lock, we have to resort to SQL context.ExecuteQuery <BackgroundWorkerJob>("SELECT TOP 1 * FROM BackgroundWorkerJobs").FirstOrDefault(); context.BackgroundWorkerJobs.InsertOnSubmit(newJob); try { context.SubmitChanges(System.Data.Linq.ConflictMode.FailOnFirstConflict); JobData job = GetJobData(newJob); jobsRequiringAction.Add(job); return(job); } catch (Exception ex) { logger.LogException(string.Format("Failed to create '{0}' with data '{1}'", jobType.AssemblyQualifiedName, data), ex); } finally { ts.Complete(); } } } return(null); }
/// <summary> /// Updates the job with the new values. /// </summary> /// <param name="job">The job.</param> /// <param name="triggerJobActionRequired">if set to <c>true</c>, cause <see cref="JobActionRequired"/> event to be raised.</param> /// <returns></returns> public bool UpdateJob(JobData job, bool triggerJobActionRequired = false) { using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.Serializable })) { using (Linq2SqlJobStoreDalDataContext context = new Linq2SqlJobStoreDalDataContext(connectionString)) { //In order to get a table lock, we have to resort to SQL var storedJob = context.ExecuteQuery <BackgroundWorkerJob>("SELECT TOP 1 * FROM BackgroundWorkerJobs WITH (TABLOCKX) 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; if (job.Schedule != null) { storedJob.ScheduleType = job.Schedule.GetType().AssemblyQualifiedName; storedJob.Schedule = Utils.SerializeObject(job.Schedule, job.Schedule.GetType()); } try { context.SubmitChanges(System.Data.Linq.ConflictMode.FailOnFirstConflict); if (triggerJobActionRequired) { jobsRequiringAction.Add(GetJobData(storedJob)); } return(true); } catch (Exception ex) { logger.LogException(string.Format("Failed to submit changes to the database."), ex); } finally { ts.Complete(); } return(false); } } } return(false); }
public JobData CreateJob(Type jobType, string data, string metaData, byte queueId, ISchedule schedule = null, Guid?uniqueId = null, string name = null, string description = null, string application = null, string group = null, TimeSpan?absoluteTimeout = null, JobStatus?jobStatus = null, DateTime?createdDate = null, bool suppressHistory = false, bool deleteWhenDone = false) { if (jobType == null) { throw new ArgumentException("jobType cannot be null."); } BackgroundWorkerJob newJob = new BackgroundWorkerJob { UniqueId = uniqueId ?? Guid.NewGuid(), AbsoluteTimeout = absoluteTimeout, CreatedDate = DateTime.Now, Data = data, MetaData = metaData, QueueId = queueId, StatusId = (int?)jobStatus ?? (schedule == null ? (int)JobStatus.Ready : (int)JobStatus.Scheduled), Type = jobType.AssemblyQualifiedName, ScheduleType = schedule != null?schedule.GetType().AssemblyQualifiedName : null, Schedule = schedule != null?Utils.SerializeObject(schedule, schedule.GetType()) : null, Instance = null, //This is just a default to show that no instance has picked this up Application = application, Group = group, Name = name, Description = description, SuppressHistory = suppressHistory, DeleteWhenDone = deleteWhenDone, NextExecutionStartDateTime = (schedule != null ? schedule.GetNextOccurrence() : null), }; using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.Serializable, Timeout = transactionTimeout })) { using (Linq2SqlJobStoreDalDataContext context = new Linq2SqlJobStoreDalDataContext(connectionString)) { context.BackgroundWorkerJobs.InsertOnSubmit(newJob); try { context.SubmitChanges(System.Data.Linq.ConflictMode.FailOnFirstConflict); ts.Complete(); JobData job = GetJobData(newJob); return(job); } catch (Exception ex) { logger.Error(string.Format("Failed to create '{0}' with data '{1}'", jobType.AssemblyQualifiedName, data), ex); } } } return(null); }
private bool QueueNextNonScheduledReadyJob(int?queueId, out JobData jobData) { jobData = 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 string queueQueryString = string.Empty; if (queueId.HasValue) { queueQueryString = string.Format(" AND QueueId = {0} ", queueId.Value); } string queryString = string.Format("SELECT TOP 1 * FROM BackgroundWorkerJobs WITH (TABLOCKX) WHERE (ScheduleType IS NULL OR ScheduleType = '') AND StatusId = {0}{1} ORDER BY [CreatedDate] Asc", "{0}", queueQueryString); var storedJob = context.ExecuteQuery <BackgroundWorkerJob>(queryString, (int)JobStatus.Ready).FirstOrDefault(); if (storedJob != null && storedJob.StatusId == (int)JobStatus.Ready) { Debug.WriteLine(string.Format("L2SQL : Queueing job {0}", storedJob.Id)); storedJob.StatusId = (int)JobStatus.Queuing; storedJob.Instance = settings.InstanceName; context.SubmitChanges(System.Data.Linq.ConflictMode.FailOnFirstConflict); Type jobType = Type.GetType(storedJob.Type); if (jobType != null) { Debug.WriteLine(string.Format("L2SQL : Queued job {0}", storedJob.Id)); jobData = GetJobData(storedJob); } else { storedJob.StatusId = (int)JobStatus.Deleted; storedJob.LastErrorMessage = string.Format("Could not load type '{0}.'", storedJob.Type); context.SubmitChanges(); } if (jobType == null) { return(false); } } } finally { ts.Complete(); } } } return(true); }
public ReadOnlyCollection <JobData> GetScheduleReadyJobs(DateTime nextExecutionStartDateTimeAtOrBefore) { using (Linq2SqlJobStoreDalDataContext context = new Linq2SqlJobStoreDalDataContext(connectionString)) { try { int scheduledStatusId = (int)JobStatus.Scheduled; var storedJobs = context.BackgroundWorkerJobs.Where(j => j.StatusId == scheduledStatusId && j.NextExecutionStartDateTime <= nextExecutionStartDateTimeAtOrBefore).OrderBy(j => j.LastExecutionStartDateTime); return(storedJobs.Select(j => GetJobData(j)).ToList().AsReadOnly()); } catch (Exception ex) { logger.Error("GetScheduleReadyJobs failed.", ex); } } return(null); }
public ReadOnlyCollection <JobData> QueueReadyJobs(byte?queueId, uint take) { List <JobData> jobData = new List <JobData>(); using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.Serializable, Timeout = transactionTimeout })) { using (Linq2SqlJobStoreDalDataContext context = new Linq2SqlJobStoreDalDataContext(connectionString)) { try { //In order to get a table lock, we have to resort to SQL string queueQueryString = string.Empty; if (queueId.HasValue) { queueQueryString = string.Format(" AND QueueId = {0} ", queueId.Value); } string queryString = string.Format("SELECT TOP {2} * FROM BackgroundWorkerJobs WITH (ROWLOCK, XLOCK) WHERE StatusId = {0}{1} ORDER BY [LastExecutionStartDateTime] ASC", (int)JobStatus.Ready, queueQueryString, take); var storedJobs = context.ExecuteQuery <BackgroundWorkerJob>(queryString).ToList(); foreach (var storedJob in storedJobs) { storedJob.StatusId = (int)JobStatus.Queuing; storedJob.Instance = settings.InstanceName; Type jobType = Type.GetType(storedJob.Type); if (jobType != null) { jobData.Add(GetJobData(storedJob)); } else { storedJob.StatusId = (int)JobStatus.Deleted; storedJob.LastErrorMessage = string.Format("Could not load type '{0}.'", storedJob.Type); } } context.SubmitChanges(System.Data.Linq.ConflictMode.FailOnFirstConflict); ts.Complete(); } catch (Exception ex) { logger.Error(string.Format("Failed to submit changes to the database."), ex); } } } return(jobData.AsReadOnly()); }
public bool SetJobStatuses(long[] jobIds, JobStatus?oldStatus, JobStatus newStatus, string errorMessage = null, string instance = "Not Specified") { if (jobIds == null || jobIds.Length == 0) { return(true); } using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.Serializable, Timeout = transactionTimeout })) { using (Linq2SqlJobStoreDalDataContext context = new Linq2SqlJobStoreDalDataContext(connectionString)) { try { //Unfortunately, can't use a single update statement here, as we need to know the exact records that were updated to trigger the requiresaction event. var storedJobs = context.ExecuteQuery <BackgroundWorkerJob>(string.Format("SELECT * FROM BackgroundWorkerJobs WITH (ROWLOCK, XLOCK) WHERE Id IN ({0})", string.Join(",", jobIds))).ToList(); foreach (var storedJob in storedJobs) { if (oldStatus.HasValue ? storedJob.StatusId == (int)oldStatus.Value : true) { storedJob.StatusId = (int)newStatus; if (errorMessage != null) { storedJob.LastErrorMessage = errorMessage; } if (instance != "Not Specified") { storedJob.Instance = instance; } } } 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); }
/// <summary> /// Tries to set the job status of the specified job. /// </summary> /// <param name="jobId">The job id.</param> /// <param name="oldStatus">The old status. This is used to ensure that job status change is what the caller expects. Use null if you don't care what the current job status is.</param> /// <param name="newStatus">The new status.</param> /// <param name="errorMessage">The optional error message.</param> /// <param name="metaData">The optional meta data.</param> /// <returns></returns> public bool SetJobStatus(long jobId, JobStatus?oldStatus, JobStatus newStatus, string errorMessage = null, string metaData = 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 var storedJob = context.ExecuteQuery <BackgroundWorkerJob>("SELECT TOP 1 * FROM BackgroundWorkerJobs WITH (TABLOCKX) WHERE Id = {0}", jobId).FirstOrDefault(); if (storedJob != null && (oldStatus.HasValue ? storedJob.StatusId == (int)oldStatus.Value : true)) { storedJob.StatusId = (int)newStatus; if (errorMessage != null) { storedJob.LastErrorMessage = errorMessage; } if (metaData != null) { storedJob.MetaData = metaData; } context.SubmitChanges(System.Data.Linq.ConflictMode.FailOnFirstConflict); jobsRequiringAction.Add(GetJobData(storedJob)); return(true); } } catch (Exception ex) { logger.LogException(string.Format("Failed to submit changes to the database."), ex); } finally { ts.Complete(); } } } return(false); }
public ReadOnlyCollection <Alert> GetAlerts(uint skip = 0, uint take = 1) { using (Linq2SqlJobStoreDalDataContext context = new Linq2SqlJobStoreDalDataContext(connectionString)) { try { var storedAlerts = context.BackgroundWorkerAlerts.OrderBy(a => a.Id).Skip((int)skip).Take((int)take); return(storedAlerts.Select(a => new Alert { Id = a.Id, JobId = a.JobId, JobHistoryId = a.JobHistoryId, Message = a.Message, }).ToList().AsReadOnly()); } catch (Exception ex) { logger.Error("GetAlerts failed.", ex); } } return(null); }
/// <summary> /// Deletes the job permanently from the job store. /// </summary> /// <param name="jobId">The job id.</param> /// <param name="deleteHistory">If set to true, the history will also be deleted.</param> /// <returns></returns> public bool DeleteJob(long jobId, bool deleteHistory = false) { using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.Serializable })) { using (Linq2SqlJobStoreDalDataContext context = new Linq2SqlJobStoreDalDataContext(connectionString)) { //In order to get a table lock, we have to resort to SQL context.ExecuteQuery <BackgroundWorkerJob>("SELECT TOP 1 * FROM BackgroundWorkerJobs").FirstOrDefault(); var job = context.BackgroundWorkerJobs.FirstOrDefault(j => j.Id == jobId); if (job != null) { if (deleteHistory) { context.BackgroundWorkerJobExecutionHistories.DeleteAllOnSubmit(context.BackgroundWorkerJobExecutionHistories.Where(jh => jh.JobId == jobId)); } context.BackgroundWorkerJobs.DeleteOnSubmit(job); try { context.SubmitChanges(System.Data.Linq.ConflictMode.FailOnFirstConflict); return(true); } catch (Exception ex) { logger.LogException(string.Format("Failed to delete job '{0}'.", jobId), ex); } finally { ts.Complete(); deletedJobs.Add(GetJobData(job)); } } } } return(false); }
public ReadOnlyCollection <JobExecutionHistory> GetJobExecutionHistories(uint skip = 0, uint take = 1, long[] jobHistoryIds = null, Guid[] jobUniqueIds = null, long[] jobIds = null, JobStatus[] jobStatuses = null, byte[] queueIds = null, string[] typeNames = null, string[] applications = null, string[] groups = null) { using (Linq2SqlJobStoreDalDataContext context = new Linq2SqlJobStoreDalDataContext(connectionString)) { try { var query = context.BackgroundWorkerJobExecutionHistories.OrderByDescending(j => j.Id).AsQueryable(); if (jobHistoryIds != null && jobHistoryIds.Length > 0) { query = query.Where(j => jobHistoryIds.Contains(j.Id)); } if (jobUniqueIds != null && jobUniqueIds.Length > 0) { query = query.Where(j => jobUniqueIds.Contains(j.JobUniqueId)); } if (jobIds != null && jobIds.Length > 0) { query = query.Where(j => jobIds.Contains(j.JobId)); } 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 <JobExecutionHistory> jobHistories = new List <JobExecutionHistory>(); var storedJobHistories = query.Skip((int)skip).Take((int)take).ToList(); foreach (var storedJobHistory in storedJobHistories) { Type jobType = Type.GetType(storedJobHistory.Type); if (jobType != null) { jobHistories.Add(new JobExecutionHistory { Id = storedJobHistory.Id, JobId = storedJobHistory.JobId, Success = storedJobHistory.Success ?? false, AbsoluteTimeout = storedJobHistory.AbsoluteTimeout, CreatedDate = storedJobHistory.CreatedDate, Instance = storedJobHistory.Instance, Data = storedJobHistory.Data, EndTime = storedJobHistory.EndDateTime, ErrorMessage = storedJobHistory.ErrorMessage, MetaData = storedJobHistory.MetaData, QueueId = storedJobHistory.QueueId, StartTime = storedJobHistory.StartDateTime, Status = (JobStatus)storedJobHistory.StatusId, JobType = jobType, Application = storedJobHistory.Application, Group = storedJobHistory.Group, Name = storedJobHistory.Name, Description = storedJobHistory.Description, JobUniqueId = storedJobHistory.JobUniqueId, }); } else { storedJobHistory.StatusId = (int)JobStatus.Deleted; storedJobHistory.ErrorMessage = string.Format("Could not load type '{0}.'", storedJobHistory.Type); context.SubmitChanges(); } } return(jobHistories.AsReadOnly()); } catch (Exception ex) { logger.Error(string.Format("Failed to get job histories from the database."), ex); } } return(null); }
public ReadOnlyCollection <JobData> GetJobs(uint skip = 0, uint take = 1, Guid[] jobUniqueIds = null, 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, Timeout = transactionTimeout })) { using (Linq2SqlJobStoreDalDataContext context = new Linq2SqlJobStoreDalDataContext(connectionString)) { try { //In order to get a table lock, we have to resort to SQL. Yeah, I said table lock. Want to get the real actual values here. context.ExecuteQuery <BackgroundWorkerJob>("SELECT TOP 1 * FROM BackgroundWorkerJobs WITH (TABLOCKX)"); var query = context.BackgroundWorkerJobs.OrderBy(j => j.CreatedDate).AsQueryable(); if (jobUniqueIds != null && jobUniqueIds.Length > 0) { query = query.Where(j => jobUniqueIds.Contains(j.UniqueId)); } 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(); ts.Complete(); return(jobs.AsReadOnly()); } catch (Exception ex) { logger.Error(string.Format("Failed to get jobs from the database."), ex); } } } return(null); }
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); }