Пример #1
0
        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;
            }
        }
Пример #2
0
        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 = "моя_твоя_непонимать");
        }
Пример #3
0
        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");
        }
Пример #4
0
        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"]);
        }
Пример #5
0
        public void GetStateData_ReturnsCorrectData()
        {
            var state = new EnqueuedState();

            DictionaryAssert.ContainsFollowingItems(
                new Dictionary<string, string>
                {
                    { "EnqueuedAt", "<UtcNow timestamp>" },
                    { "Queue", "default" }
                },
                state.Serialize());
        }
Пример #6
0
        public void IgnoreExceptions_ReturnsFalse()
        {
            var state = new EnqueuedState();

            Assert.False(state.IgnoreJobLoadException);
        }
Пример #7
0
        public void IsFinal_ReturnsFalse()
        {
            var state = new EnqueuedState();

            Assert.False(state.IsFinal);
        }
Пример #8
0
 public void SetQueue_ThrowsAnException_WhenQueueValueIsEmpty()
 {
     var state = new EnqueuedState();
     Assert.Throws<ArgumentNullException>(() => state.Queue = String.Empty);
 }
Пример #9
0
 public void Ctor_ShouldSetQueue_WhenItWasGiven()
 {
     var state = new EnqueuedState("critical");
     Assert.Equal("critical", state.Queue);
 }
Пример #10
0
 public void StateName_IsCorrect()
 {
     var state = new EnqueuedState();
     Assert.Equal(EnqueuedState.StateName, state.Name);
 }
Пример #11
0
        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;
        }
Пример #12
0
        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);
            }
        }
Пример #13
0
        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) }
                    });
            }
        }