private static bool AddFingerprintIfNotExists(IStorageConnection connection, Job job) { using (connection.AcquireDistributedLock(GetFingerprintLockKey(job), LockTimeout)) { var fingerprint = connection.GetAllEntriesFromHash(GetFingerprintKey(job)); DateTimeOffset timestamp; if (fingerprint != null && fingerprint.ContainsKey("Timestamp") && DateTimeOffset.TryParse(fingerprint["Timestamp"], null, DateTimeStyles.RoundtripKind, out timestamp) && DateTimeOffset.UtcNow <= timestamp.Add(FingerprintTimeout)) { // Actual fingerprint found, returning. return(false); } // Fingerprint does not exist, it is invalid (no `Timestamp` key), // or it is not actual (timeout expired). connection.SetRangeInHash(GetFingerprintKey(job), new Dictionary <string, string> { { "Timestamp", DateTimeOffset.UtcNow.ToString("o") } }); return(true); } }
private static void RemoveFingerprint(IStorageConnection connection, Job job) { using (connection.AcquireDistributedLock(GetFingerprintLockKey(job), LockTimeout)) using (var transaction = connection.CreateWriteTransaction()) { transaction.RemoveHash(GetFingerprintKey(job)); transaction.Commit(); } }
private void RemoveFingerprint(IStorageConnection connection, Job job) { using (connection.AcquireDistributedLock(GetFingerprintLockKey(job), LockTimeout)) using (IWriteOnlyTransaction transaction = connection.CreateWriteTransaction()) { string fingerprintKey = GetFingerprintKey(job); transaction.RemoveHash(fingerprintKey); transaction.Commit(); } }
/// <summary> /// Remove the fingerprint for the job. /// </summary> /// <param name="connection"></param> /// <param name="job"></param> private void RemoveFingerprint(IStorageConnection connection, Job job) { try { using (connection.AcquireDistributedLock(GetFingerprintWithPrefix(job, LockKeyPrefix), s_lockTimeout)) using (var transaction = connection.CreateWriteTransaction()) { transaction.RemoveHash(GetFingerprintWithPrefix(job, FingerprintPrefix)); transaction.Commit(); } } catch { // continue from exception } }
public static IDisposable AcquireDistributedRecurringJobLock( [NotNull] this IStorageConnection connection, [NotNull] string recurringJobId, TimeSpan timeout) { if (connection == null) { throw new ArgumentNullException(nameof(connection)); } if (recurringJobId == null) { throw new ArgumentNullException(nameof(recurringJobId)); } return(connection.AcquireDistributedLock($"lock:recurring-job:{recurringJobId}", timeout)); }
public static IDisposable AcquireDistributedJobLock( [NotNull] this IStorageConnection connection, [NotNull] string jobId, TimeSpan timeout) { if (connection == null) { throw new ArgumentNullException("connection"); } if (jobId == null) { throw new ArgumentNullException("jobId"); } return(connection.AcquireDistributedLock( String.Format("job:{0}:state-lock", jobId), timeout)); }
private bool AddFingerprintIfNotExists(IStorageConnection connection, Job job) { using var lck = connection.AcquireDistributedLock(GetFingerprintLockKey(job), LockTimeout); string fingerprintKey = GetFingerprintKey(job); Dictionary <string, string> fingerprint = connection.GetAllEntriesFromHash(fingerprintKey); if (fingerprint != null) { if (fingerprint.ContainsKey("Timestamp") && DateTimeOffset.TryParse(fingerprint["Timestamp"], null, DateTimeStyles.RoundtripKind, out DateTimeOffset timestamp)) { if (this.FingerprintTimeoutMinutes > 0) { var timestampWithTimeout = timestamp.Add(TimeSpan.FromMinutes(FingerprintTimeoutMinutes)); if (DateTimeOffset.UtcNow <= timestampWithTimeout) { return(false); } } else { return(false); } } } // Fingerprint does not exist, it is invalid (no `Timestamp` key), // or it is not actual (timeout expired). connection.SetRangeInHash(fingerprintKey, new Dictionary <string, string> { { "Timestamp", DateTimeOffset.UtcNow.ToString("o") }, { "MethodName", job.Method.Name }, { "TypeName", job.Type.Name } }); return(true); }
/// <summary> /// Sets <see cref="RecurringJobInfo"/> to storage which associated with <see cref="RecurringJob"/>. /// </summary> /// <param name="recurringJobInfo">The specified identifier of the RecurringJob.</param> public void SetJobData(RecurringJobInfo recurringJobInfo) { if (recurringJobInfo == null) { throw new ArgumentNullException(nameof(recurringJobInfo)); } if (recurringJobInfo.JobData == null || recurringJobInfo.JobData.Count == 0) { return; } using (_connection.AcquireDistributedLock($"recurringjobextensions-jobdata:{recurringJobInfo.RecurringJobId}", LockTimeout)) { var changedFields = new Dictionary <string, string> { [nameof(RecurringJobInfo.Enable)] = JobHelper.ToJson(recurringJobInfo.Enable), [nameof(RecurringJobInfo.JobData)] = JobHelper.ToJson(recurringJobInfo.JobData) }; _connection.SetRangeInHash($"recurring-job:{recurringJobInfo.RecurringJobId}", changedFields); } }
public static void SetTrigger(this IStorageConnection connection, string triggerName) { var jsc = (JobStorageConnection)connection; var triggerKey = GenerateTriggerKey(triggerName); var jobIds = jsc.GetAllItemsFromList(triggerKey); var client = new BackgroundJobClient(); try { using (connection.AcquireDistributedLock(triggerKey, TimeSpan.Zero)) { foreach (var jobId in jobIds) { client.ChangeState(jobId, new EnqueuedState()); } } } catch (DistributedLockTimeoutException) { // Assume already run } }
private IDisposable AcquireDistributedSetLock(IStorageConnection connection, IEnumerable <object> args) { return(connection.AcquireDistributedLock(GetDistributedLockKey(args), DistributedLockTimeout)); }
public bool TryToChangeState( string jobId, IState toState, string[] fromStates) { if (jobId == null) { throw new ArgumentNullException("jobId"); } if (toState == null) { throw new ArgumentNullException("toState"); } if (fromStates != null && fromStates.Length == 0) { throw new ArgumentException("From states array should be null or non-empty.", "fromStates"); } // To ensure that job state will be changed only from one of the // specified states, we need to ensure that other users/workers // are not able to change the state of the job during the // execution of this method. To guarantee this behavior, we are // using distributed application locks and rely on fact, that // any state transitions will be made only within a such lock. using (_connection.AcquireDistributedLock( String.Format("job:{0}:state-lock", jobId), JobLockTimeout)) { var jobData = _connection.GetJobData(jobId); if (jobData == null) { // The job does not exist. This may happen, because not // all storage backends support foreign keys. return(false); } if (fromStates != null && !fromStates.Contains(jobData.State, StringComparer.OrdinalIgnoreCase)) { return(false); } bool loadSucceeded = true; try { jobData.EnsureLoaded(); } catch (JobLoadException ex) { // If the job type could not be loaded, we are unable to // load corresponding filters, unable to process the job // and sometimes unable to change its state (the enqueued // state depends on the type of a job). if (!toState.IgnoreJobLoadException) { toState = new FailedState(ex.InnerException) { Reason = String.Format( "Can not change the state of a job to '{0}': target method was not found.", toState.Name) }; loadSucceeded = false; } } var context = new StateContext(jobId, jobData.Job, jobData.CreatedAt, _connection); var stateChanged = _stateChangeProcess.ChangeState(context, toState, jobData.State); return(loadSucceeded && stateChanged); } }