Ejemplo n.º 1
0
    public DateTime GetNextOccurrence(string cronTab, DateTime time)
    {
        var result = CrontabSchedule.Parse(cronTab);

        return(result.GetNextOccurrence(time));
    }
 public void CannotParseWhenSecondsRequired()
 {
     Assert.Throws <CrontabException>(() => CrontabSchedule.Parse("* * * * *", new ParseOptions {
         IncludingSeconds = true
     }));
 }
Ejemplo n.º 3
0
 public ScheduleInstantFacts()
 {
     _localTime = new DateTime(2012, 12, 12, 12, 12, 0, DateTimeKind.Utc);
     _schedule  = CrontabSchedule.Parse("* * * * *");
 }
        public void CannotParseNullString()
        {
            var e = Assert.Throws <ArgumentNullException>(() => CrontabSchedule.Parse(null));

            Assert.That(e.ParamName, Is.EqualTo("expression"));
        }
 public void AllTimeString()
 {
     Assert.AreEqual("* * * * *", CrontabSchedule.Parse("* * * * *").ToString());
 }
Ejemplo n.º 6
0
        /// <summary>
        /// Add the named job to the service given the execution step to perform with the specified schedule.
        /// </summary>
        /// <param name="name">The name of the job.</param>
        /// <param name="schedule">The crontab schedule string.</param>
        /// <param name="executionStep">The step to perform on execution.</param>
        public void AddJob(string name, string schedule, Action executionStep)
        {
            var cronSchedule = CrontabSchedule.Parse(schedule);

            this.AddJob(name, cronSchedule.GetNextOccurrence, executionStep);
        }
Ejemplo n.º 7
0
 public ScheduledProcessor(IServiceScopeFactory serviceScopeFactory, ITargetService targetService, IStatuService statuService
                           , IHttpClientFactory clientFactory, IEmailSender emailSender) : base(serviceScopeFactory, targetService, statuService, clientFactory, emailSender)
 {
     _schedule = CrontabSchedule.Parse(Schedule);
     _nextRun  = _schedule.GetNextOccurrence(DateTime.Now);
 }
Ejemplo n.º 8
0
        public static DateTime getNextDateTime(string token, DateTime startDate)
        {
            var schedule = CrontabSchedule.Parse(token);

            return(schedule.GetNextOccurrence(startDate));
        }
Ejemplo n.º 9
0
        public async Task ServerWideBackupShouldBackupIdleDatabase(int rounds)
        {
            const string fullBackupFrequency = "*/2 * * * *";
            var          backupParser        = CrontabSchedule.Parse(fullBackupFrequency);
            const int    maxIdleTimeInSec    = 10;

            using var server = GetNewServer(new ServerCreationOptions
            {
                CustomSettings = new Dictionary <string, string>
                {
                    [RavenConfiguration.GetKey(x => x.Databases.MaxIdleTime)]             = $"{maxIdleTimeInSec}",
                    [RavenConfiguration.GetKey(x => x.Databases.FrequencyToCheckForIdle)] = "3",
                    [RavenConfiguration.GetKey(x => x.Core.RunInMemory)] = "false"
                }
            });
            using var dispose = new DisposableAction(() => server.ServerStore.DatabasesLandlord.SkipShouldContinueDisposeCheck = false);
            server.ServerStore.DatabasesLandlord.SkipShouldContinueDisposeCheck = true;

            var dbName             = GetDatabaseName();
            var controlgroupDbName = GetDatabaseName() + "controlgroup";
            var baseBackupPath     = NewDataPath(suffix: "BackupFolder");

            using var store = new DocumentStore { Database = dbName, Urls = new[] { server.WebUrl } }.Initialize();
            store.Maintenance.Server.Send(new CreateDatabaseOperation(new DatabaseRecord(dbName)));
            store.Maintenance.Server.Send(new CreateDatabaseOperation(new DatabaseRecord(controlgroupDbName)));
            await using var keepControlGroupAlive = new RepeatableAsyncAction(async token =>
            {
                await store.Maintenance.ForDatabase(controlgroupDbName).SendAsync(new GetStatisticsOperation(), token);
                await Task.Delay(TimeSpan.FromSeconds(maxIdleTimeInSec), token);
            }).Run();

            using (var session = store.OpenAsyncSession())
            {
                await session.StoreAsync(new User { Name = "EGOR" }, "su");

                await session.SaveChangesAsync();
            }
            using (var session = store.OpenAsyncSession(controlgroupDbName))
            {
                await session.StoreAsync(new User { Name = "egor" }, "susu");

                await session.SaveChangesAsync();
            }

            var      first           = true;
            DateTime backupStartTime = default;
            GetPeriodicBackupStatusOperation periodicBackupStatusOperation = null;
            PeriodicBackupStatus             status             = null;
            PeriodicBackupStatus             controlGroupStatus = null;

            for (int i = 0; i < rounds; i++)
            {
                // let db get idle
                await WaitForValueAsync(() => Task.FromResult(server.ServerStore.IdleDatabases.Count > 0), true, 180 * 1000, 3000);

                Assert.True(1 == server.ServerStore.IdleDatabases.Count, $"IdleDatabasesCount({server.ServerStore.IdleDatabases.Count}), Round({i})");
                Assert.True(server.ServerStore.IdleDatabases.ContainsKey(store.Database), $"Round({i})");

                DateTime lastBackup;
                if (first)
                {
                    var putConfiguration = new ServerWideBackupConfiguration
                    {
                        FullBackupFrequency = fullBackupFrequency,
                        LocalSettings       = new LocalSettings {
                            FolderPath = baseBackupPath
                        },
                    };
                    var result = await store.Maintenance.Server.SendAsync(new PutServerWideBackupConfigurationOperation(putConfiguration));

                    backupStartTime = DateTime.UtcNow;

                    var serverWideConfiguration = await store.Maintenance.Server.SendAsync(new GetServerWideBackupConfigurationOperation(result.Name));

                    Assert.NotNull(serverWideConfiguration);
                    periodicBackupStatusOperation = new GetPeriodicBackupStatusOperation(serverWideConfiguration.TaskId);

                    // the configuration is applied to existing databases
                    var periodicBackupConfigurations = (await store.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(store.Database))).PeriodicBackups;
                    Assert.Equal(1, periodicBackupConfigurations.Count);
                    var backupConfigurations = (await store.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(controlgroupDbName))).PeriodicBackups;
                    Assert.Equal(1, backupConfigurations.Count);

                    first      = false;
                    lastBackup = backupStartTime;
                }
                else
                {
                    Assert.True(status.LastFullBackup.HasValue);
                    lastBackup = status.LastFullBackup.Value;
                }
                var nextBackup = backupParser.GetNextOccurrence(lastBackup);
                await Task.Delay(nextBackup - DateTime.UtcNow);

                status = await AssertWaitForNextBackup(store.Database, status);

                controlGroupStatus = await AssertWaitForNextBackup(controlgroupDbName, controlGroupStatus);

                async Task <PeriodicBackupStatus> AssertWaitForNextBackup(string db, PeriodicBackupStatus prevStatus)
                {
                    PeriodicBackupStatus nextStatus = null;

                    Assert.True(await WaitForValueAsync(async() =>
                    {
                        nextStatus = (await store.Maintenance.ForDatabase(db).SendAsync(periodicBackupStatusOperation)).Status;
                        if (nextStatus == null)
                        {
                            return(false);
                        }
                        Assert.True(nextStatus.Error?.Exception == null, nextStatus.Error?.Exception);
                        Assert.True(nextStatus.LocalBackup?.Exception == null, nextStatus.LocalBackup?.Exception);

                        return(prevStatus == null || nextStatus.LastOperationId.HasValue && nextStatus.LastOperationId > prevStatus.LastOperationId);
                    }, true), $"Round {i}");
                    return(nextStatus);
                }

                var backupsDir = Directory.GetDirectories(baseBackupPath);
                Assert.Equal(2, backupsDir.Length);

                AssertBackupDirCount(controlgroupDbName, controlGroupStatus);
                AssertBackupDirCount(store.Database, status);
                void AssertBackupDirCount(string db, PeriodicBackupStatus periodicBackupStatus)
                {
                    var backupPath = Path.Combine(baseBackupPath, db);
                    var backupDirs = Directory.GetDirectories(backupPath);

                    Assert.True(i + 1 == backupDirs.Length,
                                $"firstBackupStartTime: {backupStartTime}, checkTime: {DateTime.UtcNow}, i: {i}, " +
                                $"controlGroupBackupNum: {backupDirs.Length}, path: {backupPath}, {PrintBackups(periodicBackupStatus, backupDirs)}");
                }
            }
        }
Ejemplo n.º 10
0
 public string ToHumanString()
 {
     return(CrontabSchedule.Parse(Expression).ToString());
 }
Ejemplo n.º 11
0
        /// <summary>
        /// Creates a new schedule based on a crontab expression (eg: 0 0 * * *).
        /// Please refer to the project wiki for examples.
        /// </summary>
        /// <param name="service">The service to which the schedule should be added.</param>
        /// <param name="crontab">A crontab expression describing the schedule.</param>
        /// <returns>A part that allows chained fluent method calls.</returns>
        public static SchedulePart At(this ISchedulingService service, string crontab)
        {
            var schedule = CrontabSchedule.Parse(crontab);

            return(service.At(schedule.GetNextOccurrence));
        }
 protected ScheduledProcessor(IServiceScopeFactory serviceScopeFactory) : base(serviceScopeFactory)
 {
     _schedule = CrontabSchedule.Parse(GetCronExpression(serviceScopeFactory));
     _nextRun  = _schedule.GetNextOccurrence(DateTime.Now);
 }
Ejemplo n.º 13
0
 public ScheduledJob1(ILogger <ScheduledJob1> logger)
 {
     Logger   = logger;
     Schedule = CrontabSchedule.Parse(Cron);
     NextRun  = Schedule.GetNextOccurrence(DateTime.Now);
 }
Ejemplo n.º 14
0
        public async Task SendAlertSummary()
        {
            var compareDate = DateTime.UtcNow;
            var settings    = await GetSettingsFromDatabase();

            // If the user has indicated that they want alerts and they have specified a recipient email address, and
            // they have specified a summary alert interval (sendAlertInterval is not empty), then retrieve the
            // AlertSummaryHistory document from the database to determine if it is time to send a new alert summary.
            if (settings != null && !string.IsNullOrWhiteSpace(settings.recipientEmailAddress) && settings.SendAlerts &&
                !string.IsNullOrWhiteSpace(settings.sendAlertInterval))
            {
                var alertSummaryHistory = new AlertSummaryHistory();
                // Retrieve the alert summary history document from the alerts container.
                var response = await _alertsContainer.ReadItemAsync <AlertSummaryHistory>(WellKnown.EntityTypes.AlertSummaryHistory,
                                                                                          new PartitionKey(WellKnown.EntityTypes.AlertSummaryHistory));

                if (response.StatusCode == HttpStatusCode.OK)
                {
                    alertSummaryHistory = response.Resource;
                }

                // Retrieve the alert summary schedule from the defined cron notation.
                var schedule = CrontabSchedule.Parse(settings.sendAlertInterval);
                // Find the next schedule send date.
                var nextOccurrence =
                    schedule.GetNextOccurrence(alertSummaryHistory.summaryAlertLastSent ?? compareDate.AddDays(-1));

                if (nextOccurrence <= compareDate)
                {
                    // It is time to send a new alert summary.
                    _log.LogInformation($"Sending an alert summary based on next scheduled send date of {nextOccurrence}");

                    // Use the QueueResolver to retrieve a reference to the Azure Storage queue.
                    var alertsQueue = _queueResolver.GetQueue(WellKnown.StorageQueues.AlertQueueName);

                    // Fetch the queue attributes.
                    alertsQueue.FetchAttributes();

                    // Retrieve the cached approximate message count.
                    var cachedMessageCount = alertsQueue.ApproximateMessageCount;

                    _log.LogInformation($"Number of alert messages in the queue: {cachedMessageCount}");

                    if (cachedMessageCount.HasValue && cachedMessageCount.Value > 0)
                    {
                        // Set the batch size for number of messages to retrieve from the queue (max: 32).
                        var batchSize = 32;
                        // Determine how many loops we need to retrieve the messages, based on the batch size and number of messages.
                        var loops  = (int)Math.Ceiling((double)cachedMessageCount.Value / batchSize);
                        var alerts = new List <LogicAppAlert>();

                        // Loop through the batch size of messages until they are all retrieved.
                        for (var loop = 0; loop < loops; loop++)
                        {
                            foreach (var message in await alertsQueue.GetMessagesAsync(batchSize))
                            {
                                var alert = JsonConvert.DeserializeObject <LogicAppAlert>(message.AsString);
                                alerts.Add(alert);
                                // Delete the message from the queue.
                                await alertsQueue.DeleteMessageAsync(message);
                            }
                        }

                        var delayed = alerts.Where(a => a.status == WellKnown.Status.Delayed).ToList();

                        var payload = new LogicAppAlert
                        {
                            tripsStarted   = alerts.Count(a => a.status == WellKnown.Status.Active),
                            tripsCompleted = alerts.Count(a => a.status == WellKnown.Status.Completed),
                            tripsDelayed   = delayed.Count,
                            delayedVINs    = delayed.Count > 0 ? string.Join(", ", delayed.Select(d => d.vin)) : "None",
                            recipientEmail = settings.recipientEmailAddress,
                            isSummary      = true
                        };

                        // Send the summarized alert to the Logic App via its HTTP trigger.
                        await SendAlertToLogicApp(payload);

                        // Upsert (insert or update) the alert summary history to keep track of when we sent the alert.
                        alertSummaryHistory.summaryAlertLastSent = compareDate;
                        await _alertsContainer.UpsertItemAsync(alertSummaryHistory, new PartitionKey(alertSummaryHistory.id));
                    }
                }
            }
        }
Ejemplo n.º 15
0
 public CrontabSchedule ParseStarsNCrontab()
 {
     return(CrontabSchedule.Parse("* * * * *"));
 }
Ejemplo n.º 16
0
 protected void updateSchedule(string newSchedule)
 {
     _schedule = CrontabSchedule.Parse(newSchedule);
 }
Ejemplo n.º 17
0
 public CrontabSchedule ParseComplexNCrontab()
 {
     return(CrontabSchedule.Parse("*/10 12-20 * DEC 3"));
 }
Ejemplo n.º 18
0
        private void TryScheduleJob(
            JobStorage storage,
            IStorageConnection connection,
            string recurringJobId,
            IReadOnlyDictionary <string, string> recurringJob,
            string queueName)
        {
            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(queueName)
                    {
                        Reason = "Triggered by recurring job scheduler"
                    };

                    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);
            }
        }
 public ScheduledPublisher(IServiceScopeFactory serviceScopeFactory, ILogger <ScheduledPublisher> logger) : base(serviceScopeFactory, logger)
 {
     _schedule = CrontabSchedule.Parse(Schedule);
     _nextRun  = _schedule.GetNextOccurrence(DateTime.Now);
 }
        private async Task RunDbTasks()
        {
            using (var scope = _serviceProvider.CreateScope())
            {
                var taskRepository     = scope.ServiceProvider.GetRequiredService <ScheduledTaskRepository> ();
                var applicationWrapper = scope.ServiceProvider.GetRequiredService <ConsoleApplicationWrapper <MinecraftMessageParser> > ();

                foreach (var task in _scheduledTasks.Where(task => task.Enabled))
                {
                    CrontabSchedule schedule = null;

                    try
                    {
                        schedule = CrontabSchedule.Parse(task.CronString);
                    } catch (CrontabException ex)
                    {
                        Log.Error(ex, $"Error occurred while running ScheduledTaskId={task.ScheduledTaskId}");
                        continue;
                    }

                    // In this one instance we're going to use server local time, because that's
                    // how an end user would expect the app to work and timezones are hard.
                    var next = schedule.GetNextOccurrence(DateTime.Now.AddMinutes(-1));

                    if (DateTime.Now >= next)
                    {
                        var lastLog = await taskRepository.GetLastLogForTask(task.ScheduledTaskId);

                        if (lastLog == null || lastLog.StartTime < next)
                        {
                            var nextLog = new ScheduledTaskLog
                            {
                                StartTime       = DateTime.Now,
                                ScheduledTaskId = task.ScheduledTaskId
                            };

                            await taskRepository.SaveScheduledTaskLogAsync(nextLog);

                            try
                            {
                                switch (task.ScheduledTaskType)
                                {
                                case ScheduledTaskType.Backup:
                                    await CreateBackup(false);

                                    break;

                                case ScheduledTaskType.Command:
                                    applicationWrapper.SendInput(task.Command, null);
                                    break;
                                }

                                nextLog.CompletedTime    = DateTime.Now;
                                nextLog.CompletionStatus = "SUCCESS";

                                await taskRepository.SaveScheduledTaskLogAsync(nextLog);
                            }
                            catch (Exception ex)
                            {
                                Log.Error(ex, $"Exception occurred while running ScheduledTaskId={task.ScheduledTaskId}");

                                nextLog.CompletedTime    = DateTime.Now;
                                nextLog.CompletionStatus = "FAILED";

                                await taskRepository.SaveScheduledTaskLogAsync(nextLog);
                            }
                        }
                    }
                }
            }
        }
Ejemplo n.º 21
0
        public async Task <List <DateTime> > AskAsync(DeliveryDatesCriterion criterion)
        {
            var deliveryDates = new List <DateTime>();

            var today = criterion.Today;
            var showThreeMonthsAhead       = criterion.ShowUntil;
            var subscriptionDatesCriterion = new SubscriptionDatesForSubscriptionCriterion();
            var subscriptionDates          = await _queryBuilder.For <List <SubscriptionDate> >().WithAsync(subscriptionDatesCriterion);

            subscriptionDates = subscriptionDates.OrderByDescending(x => x.Date).ToList();
            var lastSubscriptionDate = subscriptionDates.FirstOrDefault();

            if (lastSubscriptionDate == null)
            {
                return(deliveryDates);
            }
            if (lastSubscriptionDate.Type == SubscriptionDateType.Suspend && lastSubscriptionDate.Date <= today)
            {
                return(deliveryDates);
            }

            var subscriptionActiveIntervals = new List <SubscriptionActiveInterval>();

            SubscriptionActiveInterval activeInterval = null;

            foreach (var subscriptionDate in subscriptionDates)
            {
                if (subscriptionDate.Date <= today)
                {
                    if (subscriptionActiveIntervals.Any())
                    {
                        break;
                    }

                    activeInterval = new SubscriptionActiveInterval
                    {
                        BeginAt = today,
                        EndAt   = showThreeMonthsAhead
                    };
                    subscriptionActiveIntervals.Add(activeInterval);

                    break;
                }

                if (subscriptionDate.Type == SubscriptionDateType.Suspend)
                {
                    activeInterval = new SubscriptionActiveInterval
                    {
                        BeginAt = today,
                        EndAt   = subscriptionDate.Date
                    };
                    subscriptionActiveIntervals.Add(activeInterval);
                }
                else
                {
                    if (activeInterval == null)
                    {
                        activeInterval = new SubscriptionActiveInterval(showThreeMonthsAhead);
                    }
                    activeInterval.BeginAt = subscriptionDate.Date;
                }
            }

            var deliveryIntervalForSubscriptionCriterion = new DeliveryIntervalWithTemplateForSubscriptionCriterion();
            var deliveryInterval = await _queryBuilder.For <DeliveryInterval>().WithAsync(deliveryIntervalForSubscriptionCriterion);

            foreach (var subscriptionActiveInterval in subscriptionActiveIntervals)
            {
                var cronInstance    = CrontabSchedule.Parse(deliveryInterval.CronString, CronStringFormat.WithSeconds);
                var nextOccurrences = cronInstance.GetNextOccurrences(subscriptionActiveInterval.BeginAt, subscriptionActiveInterval.EndAt);
                deliveryDates.AddRange(nextOccurrences);
            }

            return(deliveryDates);
        }
Ejemplo n.º 22
0
        public static void Main(string[] args)
        {
            var text = File.ReadAllText(args[0]);

            CrontabSchedule.Parse(text);
        }
Ejemplo n.º 23
0
 public void CannotParseEmptyString()
 {
     Assert.Throws <CrontabException>(() => CrontabSchedule.Parse(string.Empty));
 }
        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, _cronStringFormat);

            try
            {
                var startDate = JobHelper.DeserializeNullableDateTime(recurringJob["StartDate"]);
                if (startDate.HasValue)
                {
                    startDate = DateTime.SpecifyKind(startDate.Value, DateTimeKind.Utc);
                }

                var endDate = JobHelper.DeserializeNullableDateTime(recurringJob["EndDate"]);
                if (endDate.HasValue)
                {
                    endDate = DateTime.SpecifyKind(endDate.Value, DateTimeKind.Utc);
                }

                var ignoreEndDateTimeComponent = _ignoreTimeComponentInStartEndDates;
                if (recurringJob.ContainsKey(HashKeys.UseEndDateTimeComponent))
                {
                    bool.TryParse(recurringJob[HashKeys.UseEndDateTimeComponent] ?? bool.FalseString,
                                  out var useEndDateTimeComponent);
                    ignoreEndDateTimeComponent = !useEndDateTimeComponent;
                }

                var timeZone = recurringJob.ContainsKey("TimeZoneId")
                    ? TimeZoneConverter.TZConvert.GetTimeZoneInfo(recurringJob[HashKeys.TimeZoneId])
                    : TimeZoneInfo.Utc;

                var startDateForZone = startDate == null ? (DateTime?)null : TimeZoneInfo.ConvertTime(startDate.Value, TimeZoneInfo.Utc, timeZone);
                var endDateForZone   = endDate == null ? (DateTime?)null : TimeZoneInfo.ConvertTime(endDate.Value, TimeZoneInfo.Utc, timeZone);

                var nowInstant        = _instantFactory(cronSchedule, timeZone);
                var nowInstantForZone = TimeZoneInfo.ConvertTime(nowInstant.NowInstant, TimeZoneInfo.Utc, timeZone);

                // If the time component should be ignored, ignore it.
                if (_ignoreTimeComponentInStartEndDates && startDateForZone.HasValue)
                {
                    startDateForZone = startDateForZone.Value.Date;
                    // Now that we have the proper date, re-adjust the UTC versions so GetNextInstants works with the proper date range
                    startDate = TimeZoneInfo.ConvertTime(startDateForZone.Value, timeZone, TimeZoneInfo.Utc);
                }

                if (endDateForZone.HasValue && ignoreEndDateTimeComponent)
                {
                    endDateForZone = (endDateForZone.Value.Date == DateTime.MaxValue.Date)
                        ? DateTime.MaxValue
                        : endDateForZone.Value.Date.AddDays(1);
                    // Now that we have the proper date, re-adjust the UTC versions so GetNextInstants works with the proper date range
                    endDate = TimeZoneInfo.ConvertTime(endDateForZone.Value, timeZone, TimeZoneInfo.Utc);
                }

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

                var lastInstant = GetLastInstant(recurringJob, nowInstant, startDate, endDate);

                if (WithinDateRange(nowInstantForZone, startDateForZone, endDateForZone) && nowInstant.GetNextInstants(lastInstant, endDate).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(
                    $"{PluginConstants.JobType}:{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);
            }
        }
Ejemplo n.º 25
0
 public void SixPartAllTimeString()
 {
     Assert.AreEqual("* * * * * *", CrontabSchedule.Parse("* * * * * *", new ParseOptions {
         IncludingSeconds = true
     }).ToString());
 }
Ejemplo n.º 26
0
 public ScheduleInstantFacts()
 {
     _now      = new DateTime(2012, 12, 12, 12, 12, 0, DateTimeKind.Utc);
     _schedule = CrontabSchedule.Parse("* * * * *");
     _timeZone = TimeZoneInfo.Utc;
 }
Ejemplo n.º 27
0
 public ScheduledProcessor(IServiceScopeFactory serviceScopeFactory) : base(serviceScopeFactory)
 {
     _schedule = CrontabSchedule.Parse(Schedule);
     _nextRun  = _schedule.GetNextOccurrence(DateTime.Now);
 }
        public void FormatNextOccurrences_ReturnsExpectedString()
        {
            // There's no way to mock the OS TimeZoneInfo, so let's make sure this
            // works on both UTC and non-UTC
            string DateFormatter(DateTime d)
            {
                if (TimeZoneInfo.Local == TimeZoneInfo.Utc)
                {
                    return(d.ToString(TimerInfo.DateTimeFormat));
                }

                return($"{d.ToString(TimerInfo.DateTimeFormat)} ({d.ToUniversalTime().ToString(TimerInfo.DateTimeFormat)})");
            }

            DateTime now = new DateTime(2015, 9, 16, 10, 30, 00, DateTimeKind.Local);

            CronSchedule cronSchedule = new CronSchedule(CrontabSchedule.Parse("0 * * * *"));
            string       result       = TimerInfo.FormatNextOccurrences(cronSchedule, 10, now: now);

            var expectedDates = Enumerable.Range(11, 10)
                                .Select(hour => new DateTime(2015, 09, 16, hour, 00, 00, DateTimeKind.Local))
                                .Select(dateTime => $"{DateFormatter(dateTime)}\r\n")
                                .ToArray();

            string expected =
                $"The next 10 occurrences of the schedule ({cronSchedule}) will be:\r\n" +
                string.Join(string.Empty, expectedDates);

            Assert.Equal(expected, result);

            // Test the internal method with timer name specified
            string        timerName = "TestTimer";
            TimerSchedule schedule  = new DailySchedule("2:00:00");

            result = TimerInfo.FormatNextOccurrences(schedule, 5, now, timerName);

            expectedDates = Enumerable.Range(17, 5)
                            .Select(day => new DateTime(2015, 09, day, 02, 00, 00, DateTimeKind.Local))
                            .Select(dateTime => $"{DateFormatter(dateTime)}\r\n")
                            .ToArray();

            expected =
                $"The next 5 occurrences of the 'TestTimer' schedule ({schedule}) will be:\r\n" +
                string.Join(string.Empty, expectedDates);
            Assert.Equal(expected, result);

            WeeklySchedule weeklySchedule = new WeeklySchedule();

            weeklySchedule.Add(DayOfWeek.Monday, new TimeSpan(8, 0, 0));
            weeklySchedule.Add(DayOfWeek.Wednesday, new TimeSpan(9, 30, 0));
            weeklySchedule.Add(DayOfWeek.Wednesday, new TimeSpan(21, 30, 0));
            weeklySchedule.Add(DayOfWeek.Friday, new TimeSpan(10, 0, 0));

            schedule = weeklySchedule;

            result = TimerInfo.FormatNextOccurrences(schedule, 5, now, timerName);

            expected =
                $"The next 5 occurrences of the 'TestTimer' schedule ({weeklySchedule}) will be:\r\n" +
                DateFormatter(new DateTime(2015, 09, 16, 21, 30, 00, DateTimeKind.Local)) + "\r\n" +
                DateFormatter(new DateTime(2015, 09, 18, 10, 00, 00, DateTimeKind.Local)) + "\r\n" +
                DateFormatter(new DateTime(2015, 09, 21, 08, 00, 00, DateTimeKind.Local)) + "\r\n" +
                DateFormatter(new DateTime(2015, 09, 23, 09, 30, 00, DateTimeKind.Local)) + "\r\n" +
                DateFormatter(new DateTime(2015, 09, 23, 21, 30, 00, DateTimeKind.Local)) + "\r\n";

            Assert.Equal(expected, result);
        }
Ejemplo n.º 29
0
        protected virtual void TryScheduleJob(
            JobStorage storage,
            IStorageConnection connection,
            string recurringJobId,
            IReadOnlyDictionary <string, string> recurringJob)
        {
            // If a recurring job has the "V" field, then it was created by a newer
            // version. Despite we can handle 1.7.0-based recurring jobs just fine,
            // future versions may introduce new features anyway, so it's safer to
            // let other servers to handle this recurring job.
            if (recurringJob.ContainsKey("V"))
            {
                return;
            }

            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, _profiler);
                    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);
            }
        }
Ejemplo n.º 30
0
        void DoCrontabbing()
        {
            _resultBox.Clear();
            _errorProvider.SetError(_cronBox, null);
            _statusBarPanel.Text = "Ready";
            _moreButton.Enabled  = false;

            if (_crontab == null)
            {
                try
                {
                    var expression = _cronBox.Text.Trim();

                    if (expression.Length == 0)
                    {
                        return;
                    }

                    _isSixPart = expression.Split(Separators, StringSplitOptions.RemoveEmptyEntries).Length == 6;
                    _crontab   = CrontabSchedule.Parse(expression, new CrontabSchedule.ParseOptions {
                        IncludingSeconds = _isSixPart
                    });

                    _totalOccurrenceCount = 0;

                    _startTime = DateTime.ParseExact(_startTimePicker.Text,
                                                     _startTimePicker.CustomFormat, CultureInfo.InvariantCulture,
                                                     DateTimeStyles.AssumeLocal) - (_isSixPart ? TimeSpan.FromSeconds(1): TimeSpan.FromMinutes(1));
                }
                catch (CrontabException e)
                {
                    _errorProvider.SetError(_cronBox, e.Message);

                    var traceBuilder = new StringBuilder();

                    Exception traceException = e;
                    Exception lastException;

                    do
                    {
                        traceBuilder.Append(traceException.Message);
                        traceBuilder.Append("\r\n");
                        lastException  = traceException;
                        traceException = traceException.GetBaseException();
                    }while (lastException != traceException);

                    _resultBox.Text = traceBuilder.ToString();
                    return;
                }
            }

            var endTime = DateTime.ParseExact(_endTimePicker.Text,
                                              _endTimePicker.CustomFormat, CultureInfo.InvariantCulture,
                                              DateTimeStyles.AssumeLocal);

            var sb = new StringBuilder();

            var       count          = 0;
            const int maxCount       = 500;
            var       info           = DateTimeFormatInfo.CurrentInfo;
            var       dayWidth       = info.AbbreviatedDayNames.Max(s => s.Length);
            var       monthWidth     = info.AbbreviatedMonthNames.Max(s => s.Length);
            var       timeComponent  = _isSixPart ? "HH:mm:ss" : "HH:mm";
            var       timeFormat     = $"{{0,-{dayWidth}:ddd}} {{0:dd}}, {{0,-{monthWidth}:MMM}} {{0:yyyy {timeComponent}}}";
            var       lastTimeString = new string('?', string.Format(timeFormat, DateTime.MinValue).Length);

            foreach (var occurrence in _crontab.GetNextOccurrences(_startTime, endTime))
            {
                if (count + 1 > maxCount)
                {
                    break;
                }

                _startTime = occurrence;
                _totalOccurrenceCount++;
                count++;

                var timeString = string.Format(timeFormat, occurrence);

                sb.Append(timeString);
                sb.Append(" | ");

                var index = Diff(lastTimeString, timeString, 0, dayWidth, sb);
                sb.Append(' ');
                index = Diff(lastTimeString, timeString, index + 1, 2, sb);
                sb.Append(", ");
                index = Diff(lastTimeString, timeString, index + 2, monthWidth, sb);
                sb.Append(' ');
                index = Diff(lastTimeString, timeString, index + 1, 4, sb);
                sb.Append(' ');
                index = Diff(lastTimeString, timeString, index + 1, 2, sb);
                sb.Append(':');
                index = Diff(lastTimeString, timeString, index + 1, 2, sb);
                if (_isSixPart)
                {
                    sb.Append(':');
                    Diff(lastTimeString, timeString, index + 1, 2, sb);
                }

                lastTimeString = timeString;

                sb.Append("\r\n");
            }

            _moreButton.Enabled = count == maxCount;

            _statusBarPanel.Text = $"Last count = {count:N0}, Total = {_totalOccurrenceCount:N0}";

            _resultBox.Text = sb.ToString();
            _resultBox.Select(0, 0);
            _resultBox.ScrollToCaret();
        }