Exemple #1
0
        public void Execute(SlashCommand command)
        {
            try
            {
                Entities.Merge merge = Slack.MessageParser.ForMerge(command);

                merge.Verify();

                Entities.Queue queue = new Entities.Queue() { MaxWokers = 1, Name = merge.Target };
                queueBLL.Insert(queue);

                long enqueuedCount = Hangfire.JobStorage.Current.GetMonitoringApi().EnqueuedCount(queue.Name);

                IBackgroundJobClient client = new BackgroundJobClient();
                IState state = new EnqueuedState(queue.Name);

                client.Create<BusinessLogic.Merge.Base.ITrigger>(x => x.Execute(command), state);

                if(enqueuedCount > 0)
                {
                    slackBLL.DirectMessage(command, $"There {(enqueuedCount > 1 ? "are" : "is")} {enqueuedCount} {(enqueuedCount > 1 ? "merges" : "merge")} ahead of yours.");
                }
            }
            catch(ArgumentException ex)
            {
                slackBLL.DirectMessage(command, $"Failed to schedule merge: {ex.Message}");
            }
        }
        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.SerializeDateTime(state.EnqueuedAt), serializedData["EnqueuedAt"]);
        }
Exemple #5
0
 public void CreateInEnqueuedState()
 {
     #region EnqueuedState #1
     var client = new BackgroundJobClient();
     var state = new EnqueuedState("critical"); // Use the "critical" queue
      
     client.Create(() => Console.WriteLine("Hello!"), state);
     #endregion
 }
Exemple #6
0
        public void ChangeToEnqueuedState()
        {
            var jobId = "someid";

            #region EnqueuedState #2
            var client = new BackgroundJobClient();
            var state = new EnqueuedState(); // Use the default queue
            
            client.ChangeState(jobId, state, FailedState.StateName);
            #endregion
        }
        public void IgnoreExceptions_ReturnsFalse()
        {
            var state = new EnqueuedState();

            Assert.False(state.IgnoreJobLoadException);
        }
        public BackgroundJob Trigger(string recurringJobId)
        {
            if (recurringJobId == null) throw new ArgumentNullException(nameof(recurringJobId));

            using (var connection = _storage.GetConnection())
            {
                var hash = connection.GetAllEntriesFromHash($"recurring-job:{recurringJobId}");
                if (hash == null)
                {
                    return null;
                }
                
                var job = JobHelper.FromJson<InvocationData>(hash["Job"]).Deserialize();
                var state = new EnqueuedState { Reason = "Triggered using recurring job manager" };

                if (hash.ContainsKey("Queue"))
                {
                    state.Queue = hash["Queue"];
                }

                var context = new CreateContext(_storage, connection, job, state);
                context.Parameters["RecurringJobId"] = recurringJobId;
                return _factory.Create(context);
            }
        }
        public void IsFinal_ReturnsFalse()
        {
            var state = new EnqueuedState();

            Assert.False(state.IsFinal);
        }
        private void TryScheduleJob(
            JobStorage storage,
            IStorageConnection connection, 
            string recurringJobId, 
            IReadOnlyDictionary<string, string> recurringJob)
        {
            var serializedJob = JobHelper.FromJson<InvocationData>(recurringJob["Job"]);
            var job = serializedJob.Deserialize();
            var cron = recurringJob["Cron"];
            var cronSchedule = CrontabSchedule.Parse(cron);

            try
            {
                var timeZone = recurringJob.ContainsKey("TimeZoneId")
                    ? TimeZoneInfo.FindSystemTimeZoneById(recurringJob["TimeZoneId"])
                    : TimeZoneInfo.Utc;

                var nowInstant = _instantFactory(cronSchedule, timeZone);
                var changedFields = new Dictionary<string, string>();

                var lastInstant = GetLastInstant(recurringJob, nowInstant);
                
                if (nowInstant.GetNextInstants(lastInstant).Any())
                {
                    var state = new EnqueuedState { Reason = "Triggered by recurring job scheduler" };
                    if (recurringJob.ContainsKey("Queue") && !String.IsNullOrEmpty(recurringJob["Queue"]))
                    {
                        state.Queue = recurringJob["Queue"];
                    }

                    var context = new CreateContext(storage, connection, job, state);
                    context.Parameters["RecurringJobId"] = recurringJobId;

                    var backgroundJob = _factory.Create(context);
                    var jobId = backgroundJob?.Id;

                    if (String.IsNullOrEmpty(jobId))
                    {
                        Logger.Debug($"Recurring job '{recurringJobId}' execution at '{nowInstant.NowInstant}' has been canceled.");
                    }

                    changedFields.Add("LastExecution", JobHelper.SerializeDateTime(nowInstant.NowInstant));
                    changedFields.Add("LastJobId", jobId ?? String.Empty);
                }
                
                // Fixing old recurring jobs that doesn't have the CreatedAt field
                if (!recurringJob.ContainsKey("CreatedAt"))
                {
                    changedFields.Add("CreatedAt", JobHelper.SerializeDateTime(nowInstant.NowInstant));
                }
                    
                changedFields.Add("NextExecution", nowInstant.NextInstant.HasValue ? JobHelper.SerializeDateTime(nowInstant.NextInstant.Value) : null);

                connection.SetRangeInHash(
                    $"recurring-job:{recurringJobId}",
                    changedFields);
            }
#if NETFULL
            catch (TimeZoneNotFoundException ex)
            {
#else
            catch (Exception ex)
            {
                // https://github.com/dotnet/corefx/issues/7552
                if (!ex.GetType().Name.Equals("TimeZoneNotFoundException")) throw;
#endif

                Logger.ErrorException(
                    $"Recurring job '{recurringJobId}' was not triggered: {ex.Message}.",
                    ex);
            }

        }
		private void TryScheduleJob(
			JobStorage storage,
			IStorageConnection connection, 
			string recurringJobId, 
			IReadOnlyDictionary<string, string> recurringJob)
		{
			var serializedJob = JobHelper.FromJson<InvocationData>(recurringJob["Job"]);
			var job = serializedJob.Deserialize();
			var cron = recurringJob["Cron"];
			var cronSchedule = CrontabSchedule.Parse(cron);

			try
			{
				var timeZone = recurringJob.ContainsKey("TimeZoneId")
					? TimeZoneInfo.FindSystemTimeZoneById(recurringJob["TimeZoneId"])
					: TimeZoneInfo.Utc;

				var instant = _instantFactory(cronSchedule, timeZone);

				var lastExecutionTime = recurringJob.ContainsKey("LastExecution")
					? JobHelper.DeserializeDateTime(recurringJob["LastExecution"])
					: (DateTime?)null;

				var changedFields = new Dictionary<string, string>();

				const string lastJobId = "LastJobId";
				if (recurringJob.ContainsKey(lastJobId) && !string.IsNullOrWhiteSpace(recurringJob[lastJobId]))
				{
					var jobDetails = storage.GetMonitoringApi().JobDetails(recurringJob[lastJobId]);
					var finalStates = new[] {"Succeeded", "Deleted"};
					if (!jobDetails.History.Select(x => x.StateName).Any(finalStates.Contains))
					{
						Logger.Info("The recurring task " + recurringJobId + " is still running, do not schedule it more. ");
						return;
					}
				}

				if (instant.GetNextInstants(lastExecutionTime).Any())
				{

					var state = new EnqueuedState { Reason = "Triggered by recurring job scheduler" };
					if (recurringJob.ContainsKey("Queue") && !String.IsNullOrEmpty(recurringJob["Queue"]))
					{
						state.Queue = recurringJob["Queue"];
					}

					var backgroundJob = _factory.Create(new CreateContext(storage, connection, job, state));
					var jobId = backgroundJob != null ? backgroundJob.Id : null;

					if (String.IsNullOrEmpty(jobId))
					{
						Logger.DebugFormat(
							"Recurring job '{0}' execution at '{1}' has been canceled.",
							recurringJobId,
							instant.NowInstant);
					}

					changedFields.Add("LastExecution", JobHelper.SerializeDateTime(instant.NowInstant));
					changedFields.Add(lastJobId, jobId ?? String.Empty);
				}

				changedFields.Add("NextExecution", JobHelper.SerializeDateTime(instant.NextInstant));

				connection.SetRangeInHash(
					String.Format("recurring-job:{0}", recurringJobId),
					changedFields);
			}
			catch (TimeZoneNotFoundException ex)
			{
				Logger.ErrorException(
					String.Format("Recurring job '{0}' was not triggered: {1}.", recurringJobId, ex.Message),
					ex);
			}
		}
        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 instant = _instantFactory.GetInstant(cronSchedule);

            var lastExecutionTime = recurringJob.ContainsKey("LastExecution")
                ? JobHelper.DeserializeDateTime(recurringJob["LastExecution"])
                : (DateTime?)null;

            if (instant.GetMatches(lastExecutionTime).Any())
            {
                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(instant.UtcTime) },
                            { "LastJobId", jobId },
                        });
            }

            connection.SetRangeInHash(
                String.Format("recurring-job:{0}", recurringJobId),
                new Dictionary<string, string>
                {
                    {
                        "NextExecution", 
                        JobHelper.SerializeDateTime(instant.NextOccurrence)
                    }
                });
        }
 public void SetQueue_ThrowsAnException_WhenQueueValueIsEmpty()
 {
     var state = new EnqueuedState();
     Assert.Throws<ArgumentNullException>(() => state.Queue = String.Empty);
 }
        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);
            }
        }
Exemple #15
0
        private 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 = _stateMachineFactory.Create(connection);
                var enqueuedState = new EnqueuedState
                {
                    Reason = "Enqueued as a scheduled job"
                };

                stateMachine.TryToChangeState(jobId, enqueuedState, new[] { ScheduledState.StateName });

                return true;
            }
        }
        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) }
                    });
            }
        }
        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 using recurring job manager" };

                if (hash.ContainsKey("Queue"))
                {
                    state.Queue = hash["Queue"];
                }

                _factory.Create(new CreateContext(_storage, connection, job, state));
            }
        }
        private bool EnqueueNextScheduledJob()
        {
            using (var connection = _storage.GetConnection())
            using (connection.AcquireDistributedLock("locks:schedulepoller", DefaultLockTimeout))
            {
                var timestamp = JobHelper.ToTimestamp(DateTime.UtcNow);

                // TODO: it is very slow. Add batching.
                var jobId = connection
                    .GetFirstByLowestScoreFromSet("schedule", 0, timestamp);

                if (String.IsNullOrEmpty(jobId))
                {
                    // No more scheduled jobs pending.
                    return false;
                }

                var stateMachine = _stateMachineFactory.Create(connection);
                var enqueuedState = new EnqueuedState
                {
                    Reason = "Triggered scheduled job"
                };

                if (!stateMachine.ChangeState(jobId, enqueuedState, new[] { ScheduledState.StateName }))
                {
                    // When state change does not succeed, this means that background job
                    // was in a state other than Scheduled, or it was moved to a state other
                    // than Enqueued. We should remove the job identifier from the set in
                    // the first case only, but can't differentiate these cases yet.
                    using (var transaction = connection.CreateWriteTransaction())
                    {
                        transaction.RemoveFromSet("schedule", jobId);
                        transaction.Commit();
                    }
                }

                return true;
            }
        }
        private void TryScheduleJob(
            JobStorage storage,
            IStorageConnection connection, 
            string recurringJobId, 
            IReadOnlyDictionary<string, string> recurringJob)
        {
            var serializedJob = JobHelper.FromJson<InvocationData>(recurringJob["Job"]);
            var job = serializedJob.Deserialize();
            var cron = recurringJob["Cron"];
            var cronSchedule = CrontabSchedule.Parse(cron);

            try
            {
                var timeZone = recurringJob.ContainsKey("TimeZoneId")
                    ? TimeZoneInfo.FindSystemTimeZoneById(recurringJob["TimeZoneId"])
                    : TimeZoneInfo.Utc;

                var nowInstant = _instantFactory(cronSchedule, timeZone);
                var changedFields = new Dictionary<string, string>();

                var lastInstant = GetLastInstant(recurringJob, nowInstant);
                
                if (nowInstant.GetNextInstants(lastInstant).Any())
                {
                    var state = new EnqueuedState { Reason = "Triggered by recurring job scheduler" };
                    if (recurringJob.ContainsKey("Queue") && !String.IsNullOrEmpty(recurringJob["Queue"]))
                    {
                        state.Queue = recurringJob["Queue"];
                    }

                    var backgroundJob = _factory.Create(new CreateContext(storage, connection, job, state));
                    var jobId = backgroundJob != null ? backgroundJob.Id : null;

                    if (String.IsNullOrEmpty(jobId))
                    {
                        Logger.DebugFormat(
                            "Recurring job '{0}' execution at '{1}' has been canceled.",
                            recurringJobId,
                            nowInstant.NowInstant);
                    }

                    changedFields.Add("LastExecution", JobHelper.SerializeDateTime(nowInstant.NowInstant));
                    changedFields.Add("LastJobId", jobId ?? String.Empty);
                }
                
                // Fixing old recurring jobs that doesn't have the CreatedAt field
                if (!recurringJob.ContainsKey("CreatedAt"))
                {
                    changedFields.Add("CreatedAt", JobHelper.SerializeDateTime(nowInstant.NowInstant));
                }
                    
                changedFields.Add("NextExecution", nowInstant.NextInstant.HasValue ? JobHelper.SerializeDateTime(nowInstant.NextInstant.Value) : null);

                connection.SetRangeInHash(
                    String.Format("recurring-job:{0}", recurringJobId),
                    changedFields);
            }
            catch (TimeZoneNotFoundException ex)
            {
                Logger.ErrorException(
                    String.Format("Recurring job '{0}' was not triggered: {1}.", recurringJobId, ex.Message),
                    ex);
            }
        }
 public void StateName_IsCorrect()
 {
     var state = new EnqueuedState();
     Assert.Equal(EnqueuedState.StateName, state.Name);
 }
        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 parts = cron.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
			var cronSchedule = CrontabSchedule.Parse(cron, new CrontabSchedule.ParseOptions { IncludingSeconds = (parts.Length >= 6) });

            try
            {
                var timeZone = recurringJob.ContainsKey("TimeZoneId")
                ? TimeZoneInfo.FindSystemTimeZoneById(recurringJob["TimeZoneId"])
                : TimeZoneInfo.Utc;

                var instant = _instantFactory.GetInstant(cronSchedule, timeZone);

                var lastExecutionTime = recurringJob.ContainsKey("LastExecution")
                    ? JobHelper.DeserializeDateTime(recurringJob["LastExecution"])
                    : (DateTime?)null;

                var changedFields = new Dictionary<string, string>();

                if (instant.GetNextInstants(lastExecutionTime).Any())
                {
                    var state = new EnqueuedState { Reason = "Triggered by recurring job scheduler" };
                    var jobId = _client.Create(job, state);

                    if (String.IsNullOrEmpty(jobId))
                    {
                        Logger.DebugFormat(
                            "Recurring job '{0}' execution at '{1}' has been canceled.",
                            recurringJobId,
                            instant.NowInstant);
                    }

                    changedFields.Add("LastExecution", JobHelper.SerializeDateTime(instant.NowInstant));
                    changedFields.Add("LastJobId", jobId ?? String.Empty);
                }

                changedFields.Add("NextExecution", JobHelper.SerializeDateTime(instant.NextInstant));

                connection.SetRangeInHash(
                    String.Format("recurring-job:{0}", recurringJobId),
                    changedFields);
            }
            catch (TimeZoneNotFoundException ex)
            {
                Logger.ErrorException(
                    String.Format("Recurring job '{0}' was not triggered: {1}.", recurringJobId, ex.Message),
                    ex);
            }
        }
 public void Ctor_ShouldSetQueue_WhenItWasGiven()
 {
     var state = new EnqueuedState("critical");
     Assert.Equal("critical", state.Queue);
 }