public bool EnqueueNextScheduledJob() { using (var connection = _storage.GetConnection()) { var timestamp = JobHelper.ToTimestamp(DateTime.UtcNow); // TODO: it is very slow. Add batching. var jobId = connection .GetFirstByLowestScoreFromSet("schedule", 0, timestamp); if (String.IsNullOrEmpty(jobId)) { return false; } var stateMachine = new StateMachine(connection); var enqueuedState = new EnqueuedState { Reason = "Enqueued as a scheduled job" }; stateMachine.TryToChangeState(jobId, enqueuedState, new [] { ScheduledState.StateName }); return true; } }
public void SetQueue_ThrowsAnException_WhenValueIsNotInAGivenFormat() { var state = new EnqueuedState(); Assert.Throws<ArgumentException>(() => state.Queue = "UppercaseLetters"); Assert.Throws<ArgumentException>(() => state.Queue = "punctuation:un-allowed"); Assert.Throws<ArgumentException>(() => state.Queue = "моя_твоя_непонимать"); }
public void SetQueue_DoesNotThrowException_WhenValueIsInACorrectFormat() { var state = new EnqueuedState(); Assert.DoesNotThrow(() => state.Queue = "lowercasedcharacters"); Assert.DoesNotThrow(() => state.Queue = "underscores_allowed"); Assert.DoesNotThrow(() => state.Queue = "1234567890_allowed"); }
public void SerializeData_ReturnsCorrectData() { var state = new EnqueuedState(); var serializedData = state.SerializeData(); Assert.Equal(state.Queue, serializedData["Queue"]); Assert.Equal(JobHelper.ToStringTimestamp(state.EnqueuedAt), serializedData["EnqueuedAt"]); }
public void GetStateData_ReturnsCorrectData() { var state = new EnqueuedState(); DictionaryAssert.ContainsFollowingItems( new Dictionary<string, string> { { "EnqueuedAt", "<UtcNow timestamp>" }, { "Queue", "default" } }, state.Serialize()); }
public void IgnoreExceptions_ReturnsFalse() { var state = new EnqueuedState(); Assert.False(state.IgnoreJobLoadException); }
public void IsFinal_ReturnsFalse() { var state = new EnqueuedState(); Assert.False(state.IsFinal); }
public void SetQueue_ThrowsAnException_WhenQueueValueIsEmpty() { var state = new EnqueuedState(); Assert.Throws<ArgumentNullException>(() => state.Queue = String.Empty); }
public void Ctor_ShouldSetQueue_WhenItWasGiven() { var state = new EnqueuedState("critical"); Assert.Equal("critical", state.Queue); }
public void StateName_IsCorrect() { var state = new EnqueuedState(); Assert.Equal(EnqueuedState.StateName, state.Name); }
private bool RequeueJobIfTimedOut(IRedisClient redis, string jobId, string queue) { var flags = redis.GetValuesFromHash( String.Format("hangfire:job:{0}", jobId), "Fetched", "Checked"); var fetched = flags[0]; var @checked = flags[1]; if (String.IsNullOrEmpty(fetched) && String.IsNullOrEmpty(@checked)) { // If the job does not have these flags set, then it is // in the implicit 'Fetched' state. This state has no // information about the time it was fetched. So we // can not do anything with the job in this state, because // there are two options: // 1. It is going to move to the implicit 'Fetched' state // in a short time. // 2. It will stay in the 'Fetched' state forever due to // its processing server is dead. // To ensure its server is dead, we'll move the job to // the implicit 'Checked' state with the current timestamp // and will not do anything else at this pass of the watcher. // If job's state will still be 'Checked' on the later passes // and after the CheckedTimeout expired, then the server // is dead, and we'll re-queue the job. redis.SetEntryInHash( String.Format("hangfire:job:{0}", jobId), "Checked", JobHelper.ToStringTimestamp(DateTime.UtcNow)); // Checkpoint #1-2. The job is in the implicit 'Checked' state. // It will be re-queued after the CheckedTimeout will be expired. } else { if (TimedOutByFetchedTime(fetched) || TimedOutByCheckedTime(fetched, @checked)) { var stateMachine = new StateMachine(new RedisConnection(_storage, redis)); var state = new EnqueuedState{ Reason = "Re-queued due to time out" }; stateMachine.TryToChangeState( jobId, state, new [] { EnqueuedState.StateName, ProcessingState.StateName }); RedisConnection.RemoveFromFetchedList(redis, queue, jobId); return true; } } return false; }
public void Trigger([NotNull] string recurringJobId) { if (recurringJobId == null) throw new ArgumentNullException("recurringJobId"); using (var connection = _storage.GetConnection()) { var hash = connection.GetAllEntriesFromHash(String.Format("recurring-job:{0}", recurringJobId)); if (hash == null) { return; } var job = JobHelper.FromJson<InvocationData>(hash["Job"]).Deserialize(); var state = new EnqueuedState { Reason = "Triggered" }; _client.Create(job, state); } }
private void TryScheduleJob(IStorageConnection connection, string recurringJobId, Dictionary<string, string> recurringJob) { var serializedJob = JobHelper.FromJson<InvocationData>(recurringJob["Job"]); var job = serializedJob.Deserialize(); var cron = recurringJob["Cron"]; var cronSchedule = CrontabSchedule.Parse(cron); var currentTime = _dateTimeProvider.CurrentDateTime; if (recurringJob.ContainsKey("NextExecution")) { var nextExecution = JobHelper.DeserializeDateTime(recurringJob["NextExecution"]); if (nextExecution <= currentTime) { var state = new EnqueuedState { Reason = "Triggered by recurring job scheduler" }; var jobId = _client.Create(job, state); connection.SetRangeInHash( String.Format("recurring-job:{0}", recurringJobId), new Dictionary<string, string> { { "LastExecution", JobHelper.SerializeDateTime(currentTime) }, { "LastJobId", jobId }, { "NextExecution", JobHelper.SerializeDateTime(_dateTimeProvider.GetNextOccurrence(cronSchedule)) } }); } } else { var nextExecution = _dateTimeProvider.GetNextOccurrence(cronSchedule); connection.SetRangeInHash( String.Format("recurring-job:{0}", recurringJobId), new Dictionary<string, string> { { "NextExecution", JobHelper.SerializeDateTime(nextExecution) } }); } }