public async Task ClockSkew_IsNotCalculatedPastDue()
        {
            // First, invoke a function with clock skew. This will store the next status back in the
            // 'updatedStatus' variable.
            CreateTestListener("0 0 0 * * *");
            var status = new ScheduleStatus
            {
                Last        = new DateTime(2016, 3, 4),
                Next        = new DateTime(2016, 3, 5),
                LastUpdated = new DateTime(2016, 3, 4)
            };
            DateTime       invocationTime = status.Next.AddMilliseconds(-1);
            ScheduleStatus updatedStatus  = null;

            _mockScheduleMonitor.Setup(p => p.UpdateStatusAsync(_testTimerName, It.IsAny <ScheduleStatus>()))
            .Callback <string, ScheduleStatus>((n, s) => updatedStatus = s)
            .Returns(Task.FromResult(true));
            _listener.ScheduleStatus = status;
            await _listener.InvokeJobFunction(invocationTime, isPastDue : false, runOnStartup : false);

            _listener.Dispose();

            // Now, use that status variable to calculate past due (this ultimately calls the base class implementation).
            // This ensures we do not consider clock skewed functions as past due -- this was previously a bug.
            // Use a new mock monitor so we can CallBase on it without affecting the class-level one.
            var mockMonitor = new Mock <ScheduleMonitor>();

            mockMonitor.CallBase = true;
            DateTime hostStartTime = new DateTime(2016, 3, 5, 1, 0, 0);
            TimeSpan pastDue       = await mockMonitor.Object.CheckPastDueAsync(_testTimerName, hostStartTime, _schedule, updatedStatus);

            Assert.Equal(TimeSpan.Zero, pastDue);
            _mockScheduleMonitor.VerifyAll();
        }
Example #2
0
        private async Task CheckPastDue_ScheduleChange_Longer(bool lastSet, bool lastUpdatedSet)
        {
            DateTime now = DateTime.Parse("1/1/2017 9:35");

            ScheduleStatus status = new ScheduleStatus
            {
                Last        = lastSet ? DateTime.Parse("1/1/2017 9:00") : default(DateTime),
                Next        = DateTime.Parse("1/1/2017 10:00"),
                LastUpdated = lastUpdatedSet ? DateTime.Parse("1/1/2017 9:00") : default(DateTime)
            };

            MockScheduleMonitor monitor = new MockScheduleMonitor();

            // change to daily schedule (status is hourly)
            TimeSpan pastDueAmount = await monitor.CheckPastDueAsync(_timerName, now, _dailySchedule, status);

            Assert.Equal(TimeSpan.Zero, pastDueAmount);

            DateTime expectedNext = DateTime.Parse("1/2/2017 0:00");

            Assert.Equal(default(DateTime), monitor.CurrentStatus.Last);
            Assert.Equal(expectedNext, monitor.CurrentStatus.Next);

            if (lastUpdatedSet || lastSet)
            {
                Assert.Equal(DateTime.Parse("1/1/2017 9:00"), monitor.CurrentStatus.LastUpdated);
            }
            else
            {
                // Legacy behavior -- before 'LastUpdated' was added.

                Assert.Equal(now, monitor.CurrentStatus.LastUpdated);
            }
        }
Example #3
0
        public async Task CheckPastDue_NowPastNext(bool lastSet, bool lastUpdatedSet)
        {
            // Move the time 1 second ahead of 'Next'. We should catch this as past due.
            DateTime now = DateTime.Parse("1/1/2017 10:00:01");

            ScheduleStatus status = new ScheduleStatus
            {
                Last        = lastSet ? DateTime.Parse("1/1/2017 9:00") : default(DateTime),
                Next        = DateTime.Parse("1/1/2017 10:00"),
                LastUpdated = lastUpdatedSet ? DateTime.Parse("1/1/2017 9:00") : default(DateTime)
            };

            MockScheduleMonitor monitor = new MockScheduleMonitor();

            TimeSpan pastDueAmount = await monitor.CheckPastDueAsync(_timerName, now, _hourlySchedule, status);

            if (lastUpdatedSet || lastSet)
            {
                Assert.Equal(TimeSpan.FromSeconds(1), pastDueAmount);
                Assert.Null(monitor.CurrentStatus);
            }
            else
            {
                // Legacy behavior -- 'LastUpdated' fixed this. The schedule didn't change and we're past due,
                //      but we miss it because there is no 'Last' value, which we require to calculate the 'Next'
                //      value. It also shouldn't register as a schedule change.
                Assert.Equal(TimeSpan.Zero, pastDueAmount);
                Assert.Equal(default(DateTime), monitor.CurrentStatus.Last);
                Assert.Equal(DateTime.Parse("1/1/2017 11:00"), monitor.CurrentStatus.Next);
                Assert.Equal(now, monitor.CurrentStatus.LastUpdated);
            }
        }
        public async Task CheckPastDueAsync_ReturnsExpectedResult()
        {
            Mock <TimerSchedule> mockSchedule = new Mock <TimerSchedule>(MockBehavior.Strict);
            DateTime             now          = DateTime.Now;
            DateTime             next         = now + TimeSpan.FromDays(1);
            ScheduleStatus       status       = new ScheduleStatus
            {
                Last = now,
                Next = next
            };

            mockSchedule.Setup(p => p.GetNextOccurrence(It.IsAny <DateTime>())).Returns(next);
            TimeSpan pastDueAmount = await _monitor.CheckPastDueAsync(_testTimerName, now, mockSchedule.Object, status);

            Assert.Equal(TimeSpan.Zero, pastDueAmount);

            now           = now + TimeSpan.FromHours(23);
            pastDueAmount = await _monitor.CheckPastDueAsync(_testTimerName, now, mockSchedule.Object, status);

            Assert.Equal(TimeSpan.Zero, pastDueAmount);

            now           = now + TimeSpan.FromHours(1);
            pastDueAmount = await _monitor.CheckPastDueAsync(_testTimerName, now, mockSchedule.Object, status);

            Assert.Equal(TimeSpan.Zero, pastDueAmount);

            now           = now + TimeSpan.FromHours(1);
            pastDueAmount = await _monitor.CheckPastDueAsync(_testTimerName, now, mockSchedule.Object, status);

            Assert.Equal(TimeSpan.FromHours(1), pastDueAmount);
        }
        public async Task UpdateAsync_WritesStatusToFile()
        {
            DateTime now          = DateTime.Now;
            DateTime expectedNext = DateTime.Now + TimeSpan.FromMinutes(1);

            File.Delete(_statusFile);
            Assert.False(File.Exists(_statusFile));

            ScheduleStatus status = new ScheduleStatus
            {
                Last = now,
                Next = expectedNext
            };
            await _monitor.UpdateStatusAsync(_testTimerName, status);

            Assert.True(File.Exists(_statusFile));
            VerifyScheduleStatus(now, expectedNext);

            now          = expectedNext;
            expectedNext = now + TimeSpan.FromMinutes(1);
            status       = new ScheduleStatus
            {
                Last = now,
                Next = expectedNext
            };
            await _monitor.UpdateStatusAsync(_testTimerName, status);

            VerifyScheduleStatus(now, expectedNext);
        }
        public async Task StartAsync(CancellationToken cancellationToken)
        {
            ThrowIfDisposed();

            if (_timer != null && _timer.Enabled)
            {
                throw new InvalidOperationException("The listener has already been started.");
            }

            // if schedule monitoring is enabled, record (or initialize)
            // the current schedule status
            bool isPastDue = false;

            // we use DateTime.Now rather than DateTime.UtcNow to allow the local machine to set the time zone. In Azure this will be
            // UTC by default, but can be configured to use any time zone if it makes scheduling easier.
            DateTime now = DateTime.Now;

            _logger.LogDebug($"The '{_functionShortName}' timer is using the schedule '{_schedule.ToString()}' and the local time zone: '{TimeZoneInfo.Local.DisplayName}'");

            if (ScheduleMonitor != null)
            {
                // check to see if we've missed an occurrence since we last started.
                // If we have, invoke it immediately.
                ScheduleStatus = await ScheduleMonitor.GetStatusAsync(_timerLookupName);

                _logger.LogDebug($"Function '{_functionShortName}' initial status: Last='{ScheduleStatus?.Last.ToString("o")}', Next='{ScheduleStatus?.Next.ToString("o")}', LastUpdated='{ScheduleStatus?.LastUpdated.ToString("o")}'");
                TimeSpan pastDueDuration = await ScheduleMonitor.CheckPastDueAsync(_timerLookupName, now, _schedule, ScheduleStatus);

                isPastDue = pastDueDuration != TimeSpan.Zero;
            }

            if (ScheduleStatus == null)
            {
                // no schedule status has been stored yet, so initialize
                ScheduleStatus = new ScheduleStatus
                {
                    Last = default(DateTime),
                    Next = _schedule.GetNextOccurrence(now)
                };
            }

            if (isPastDue)
            {
                _logger.LogDebug($"Function '{_functionShortName}' is past due on startup. Executing now.");
                await InvokeJobFunction(now, isPastDue : true, originalSchedule : ScheduleStatus.Next);
            }
            else if (_attribute.RunOnStartup)
            {
                // The job is configured to run immediately on startup
                _logger.LogDebug($"Function '{_functionShortName}' is configured to run on startup. Executing now.");
                await InvokeJobFunction(now, runOnStartup : true);
            }

            // log the next several occurrences to console for visibility
            string nextOccurrences = TimerInfo.FormatNextOccurrences(_schedule, 5, functionShortName: _functionShortName);

            _logger.LogInformation(nextOccurrences);

            StartTimer(DateTime.Now);
        }
Example #7
0
 public ScheduleOverviewResource(
     int scheduleId,
     string wellName,
     string @operator,
     DateTime fracStartDate,
     DateTime fracEndDate,
     int duration,
     string api,
     double surfaceLat,
     double surfaceLong,
     double bottomholeLat,
     double bottomholeLong,
     string tvd,
     int?startIn,
     ScheduleStatus status)
 {
     this.ScheduleId     = scheduleId;
     this.WellName       = wellName;
     this.Operator       = @operator;
     this.FracStartDate  = fracStartDate;
     this.FracEndDate    = fracEndDate;
     this.Duration       = duration;
     this.Api            = api;
     this.SurfaceLat     = surfaceLat;
     this.SurfaceLong    = surfaceLong;
     this.BottomholeLat  = bottomholeLat;
     this.BottomholeLong = bottomholeLong;
     this.Tvd            = tvd;
     this.StartIn        = startIn;
     this.Status         = status;
 }
        public async Task Timer_CannotHaveNegativeInterval()
        {
            CreateTestListener("* * * * * *", useMonitor: true);

            ScheduleStatus status = new ScheduleStatus();

            _mockScheduleMonitor.Setup(p => p.GetStatusAsync(_testTimerName)).ReturnsAsync(status);

            // Make sure we invoke b/c we're past due.
            _mockScheduleMonitor.Setup(p => p.CheckPastDueAsync(_testTimerName, It.IsAny <DateTime>(), It.IsAny <TimerSchedule>(), status))
            .ReturnsAsync(TimeSpan.FromMilliseconds(1));

            // Use the monitor to sleep for a second. This ensures that we recalculate the Next value before
            // starting the timer. Otherwise, you can end up with a negative interval.
            bool updateCalled = false;

            _mockScheduleMonitor.Setup(p => p.UpdateStatusAsync(_testTimerName, It.IsAny <ScheduleStatus>()))
            .Callback(() =>
            {
                // only sleep for the first call
                if (!updateCalled)
                {
                    Thread.Sleep(1000);
                }
                updateCalled = true;
            })
            .Returns(Task.FromResult(true));

            await _listener.StartAsync(CancellationToken.None);

            Assert.True(updateCalled);
        }
        internal async Task InvokeJobFunction(DateTime lastOccurrence, bool isPastDue = false)
        {
            CancellationToken     token     = _cancellationTokenSource.Token;
            TimerInfo             timerInfo = new TimerInfo(_schedule, _scheduleStatus, isPastDue);
            TriggeredFunctionData input     = new TriggeredFunctionData
            {
                TriggerValue = timerInfo
            };

            try
            {
                FunctionResult result = await _executor.TryExecuteAsync(input, token);

                if (!result.Succeeded)
                {
                    token.ThrowIfCancellationRequested();
                }
            }
            catch
            {
                // We don't want any function errors to stop the execution
                // schedule. Errors will be logged to Dashboard already.
            }

            if (ScheduleMonitor != null)
            {
                _scheduleStatus = new ScheduleStatus
                {
                    Last = lastOccurrence,
                    Next = _schedule.GetNextOccurrence(lastOccurrence)
                };
                await ScheduleMonitor.UpdateStatusAsync(_timerName, _scheduleStatus);
            }
        }
        public async Task InvokeJobFunction_UpdatesScheduleMonitor_AccountsForSkew(string schedule, bool useMonitor)
        {
            CreateTestListener(schedule, useMonitor);

            var status = new ScheduleStatus
            {
                Last = new DateTime(2016, 3, 4),
                Next = new DateTime(2016, 3, 5)
            };

            // Run the function 1 millisecond before it's next scheduled run.
            DateTime invocationTime = status.Next.AddMilliseconds(-1);

            // It should not use the same 'Next' value twice in a row.
            DateTime expectedNextOccurrence = new DateTime(2016, 3, 6);

            bool monitorCalled = false;

            _mockScheduleMonitor.Setup(p => p.UpdateStatusAsync(_testTimerName,
                                                                It.Is <ScheduleStatus>(q => q.Last == status.Next && q.Next == expectedNextOccurrence)))
            .Callback(() => monitorCalled = true)
            .Returns(Task.FromResult(true));

            // Initialize the _scheduleStatus
            _listener.ScheduleStatus = status;

            await _listener.InvokeJobFunction(invocationTime, isPastDue : false, runOnStartup : false);

            _listener.Dispose();

            Assert.Equal(status.Next, _listener.ScheduleStatus.Last);
            Assert.Equal(expectedNextOccurrence, _listener.ScheduleStatus.Next);
            Assert.Equal(monitorCalled, useMonitor);
        }
Example #11
0
        public async Task UpdateStatusAsync_MultipleFunctions()
        {
            // update status for 3 functions
            ScheduleStatus expected = new ScheduleStatus
            {
                Last = DateTime.Now.Subtract(TimeSpan.FromMinutes(5)),
                Next = DateTime.Now.AddMinutes(5)
            };

            for (int i = 0; i < 3; i++)
            {
                await _scheduleMonitor.UpdateStatusAsync(TestTimerName + i.ToString(), expected);
            }

            var segments = await _scheduleMonitor.TimerStatusDirectory.ListBlobsSegmentedAsync(
                useFlatBlobListing : true,
                blobListingDetails : BlobListingDetails.None,
                maxResults : null,
                currentToken : null,
                options : null,
                operationContext : null);

            var statuses = segments.Results.Cast <CloudBlockBlob>().ToArray();

            Assert.Equal(3, statuses.Length);
            Assert.Equal("timers/testhostid/TestProgram.TestTimer0/status", statuses[0].Name);
            Assert.Equal("timers/testhostid/TestProgram.TestTimer1/status", statuses[1].Name);
            Assert.Equal("timers/testhostid/TestProgram.TestTimer2/status", statuses[2].Name);
        }
        public async Task RunInitialStatusTestAsync(ScheduleStatus initialStatus, string expected)
        {
            _mockScheduleMonitor
            .Setup(m => m.GetStatusAsync(_testTimerName))
            .ReturnsAsync(initialStatus);
            _mockScheduleMonitor
            .Setup(m => m.CheckPastDueAsync(_testTimerName, It.IsAny <DateTime>(), _schedule, It.IsAny <ScheduleStatus>()))
            .ReturnsAsync(TimeSpan.Zero);

            await _listener.StartAsync(CancellationToken.None);

            await _listener.StopAsync(CancellationToken.None);

            _listener.Dispose();

            LogMessage[] verboseTraces = _logger.GetLogMessages()
                                         .Where(m => m.Level == LogLevel.Debug)
                                         .OrderBy(t => t.Timestamp)
                                         .ToArray();

            Assert.Equal(3, verboseTraces.Length);
            Assert.Contains("timer is using the schedule 'Cron: '0 * * * * *'' and the local time zone:", verboseTraces[0].FormattedMessage);
            Assert.Equal(expected, verboseTraces[1].FormattedMessage);
            Assert.Contains($"Timer for '{_functionShortName}' started with interval", verboseTraces[2].FormattedMessage);
        }
Example #13
0
        public async Task StartAsync(CancellationToken cancellationToken)
        {
            ThrowIfDisposed();

            if (_timer != null && _timer.Enabled)
            {
                throw new InvalidOperationException("The listener has already been started.");
            }

            // if schedule monitoring is enabled, record (or initialize)
            // the current schedule status
            bool     isPastDue = false;
            DateTime now       = DateTime.Now;

            if (ScheduleMonitor != null)
            {
                // check to see if we've missed an occurrence since we last started.
                // If we have, invoke it immediately.
                _scheduleStatus = await ScheduleMonitor.GetStatusAsync(_timerName);

                TimeSpan pastDueDuration = await ScheduleMonitor.CheckPastDueAsync(_timerName, now, _schedule, _scheduleStatus);

                isPastDue = pastDueDuration != TimeSpan.Zero;

                if (_scheduleStatus == null)
                {
                    // no schedule status has been stored yet, so initialize
                    _scheduleStatus = new ScheduleStatus
                    {
                        Last = default(DateTime),
                        Next = _schedule.GetNextOccurrence(now)
                    };
                }
            }

            if (isPastDue)
            {
                _trace.Verbose(string.Format("Function '{0}' is past due on startup. Executing now.", _timerName));
                await InvokeJobFunction(now, true);
            }
            else if (_attribute.RunOnStartup)
            {
                // The job is configured to run immediately on startup
                _trace.Verbose(string.Format("Function '{0}' is configured to run on startup. Executing now.", _timerName));
                await InvokeJobFunction(now);
            }

            // log the next several occurrences to console for visibility
            string nextOccurrences = TimerInfo.FormatNextOccurrences(_schedule, 5);

            _trace.Verbose(nextOccurrences);

            // start the timer
            now = DateTime.Now;
            DateTime nextOccurrence = _schedule.GetNextOccurrence(now);
            TimeSpan nextInterval   = nextOccurrence - now;

            StartTimer(nextInterval);
        }
Example #14
0
 public void Resume()
 {
     if (this.Scheduler.IsStarted)
     {
         this.Scheduler.PauseAll();
         this.GetScheduleStatus = ScheduleStatus.Starting;
     }
 }
Example #15
0
 public void Pause()
 {
     if (this.Scheduler.IsStarted)
     {
         this.Scheduler.PauseAll();
         this.GetScheduleStatus = ScheduleStatus.Pause;
     }
 }
Example #16
0
 private static string Linethrough(ScheduleStatus status)
 {
     if (status == ScheduleStatus.Removed)
     {
         return("text-decoration: line-through;");
     }
     return(String.Empty);
 }
Example #17
0
        public async Task StartAsync(CancellationToken cancellationToken)
        {
            ThrowIfDisposed();

            if (_timer != null && _timer.Enabled)
            {
                throw new InvalidOperationException("The listener has already been started.");
            }

            // if schedule monitoring is enabled, record (or initialize)
            // the current schedule status
            bool isPastDue = false;

            // we use DateTime.Now rather than DateTime.UtcNow to allow the local machine to set the time zone. In Azure this will be
            // UTC by default, but can be configured to use any time zone if it makes scheduling easier.
            DateTime now = DateTime.Now;

            if (ScheduleMonitor != null)
            {
                // check to see if we've missed an occurrence since we last started.
                // If we have, invoke it immediately.
                ScheduleStatus = await ScheduleMonitor.GetStatusAsync(_timerName);

                TimeSpan pastDueDuration = await ScheduleMonitor.CheckPastDueAsync(_timerName, now, _schedule, ScheduleStatus);

                isPastDue = pastDueDuration != TimeSpan.Zero;
            }

            if (ScheduleStatus == null)
            {
                // no schedule status has been stored yet, so initialize
                ScheduleStatus = new ScheduleStatus
                {
                    Last = default(DateTime),
                    Next = _schedule.GetNextOccurrence(now)
                };
            }

            if (isPastDue)
            {
                _trace.Verbose(string.Format("Function '{0}' is past due on startup. Executing now.", _timerName));
                await InvokeJobFunction(now, isPastDue : true);
            }
            else if (_attribute.RunOnStartup)
            {
                // The job is configured to run immediately on startup
                _trace.Verbose(string.Format("Function '{0}' is configured to run on startup. Executing now.", _timerName));
                await InvokeJobFunction(now, runOnStartup : true);
            }

            // log the next several occurrences to console for visibility
            string nextOccurrences = TimerInfo.FormatNextOccurrences(_schedule, 5);

            _trace.Info(nextOccurrences);

            StartTimer(DateTime.Now);
        }
Example #18
0
        /// <summary>
        /// Invokes the job function.
        /// </summary>
        /// <param name="invocationTime">The time of the invocation, likely DateTime.Now.</param>
        /// <param name="isPastDue">True if the invocation is because the invocation is due to a past due timer.</param>
        /// <param name="runOnStartup">True if the invocation is because the timer is configured to run on startup.</param>
        internal async Task InvokeJobFunction(DateTime invocationTime, bool isPastDue = false, bool runOnStartup = false)
        {
            CancellationToken token           = _cancellationTokenSource.Token;
            ScheduleStatus    timerInfoStatus = null;

            if (ScheduleMonitor != null)
            {
                timerInfoStatus = ScheduleStatus;
            }
            TimerInfo             timerInfo = new TimerInfo(_schedule, timerInfoStatus, isPastDue);
            TriggeredFunctionData input     = new TriggeredFunctionData
            {
                TriggerValue = timerInfo
            };

            try
            {
                FunctionResult result = await _executor.TryExecuteAsync(input, token);

                if (!result.Succeeded)
                {
                    token.ThrowIfCancellationRequested();
                }
            }
            catch
            {
                // We don't want any function errors to stop the execution
                // schedule. Errors will be logged to Dashboard already.
            }

            // If the trigger fired before it was officially scheduled (likely under 1 second due to clock skew),
            // adjust the invocation time forward for the purposes of calculating the next occurrence.
            // Without this, it's possible to set the 'Next' value to the same time twice in a row,
            // which results in duplicate triggers if the site restarts.
            DateTime adjustedInvocationTime = invocationTime;

            if (!isPastDue && !runOnStartup && ScheduleStatus?.Next > invocationTime)
            {
                adjustedInvocationTime = ScheduleStatus.Next;
            }

            // Create the Last value with the adjustedInvocationTime; otherwise, the listener will
            // consider this a schedule change when the host next starts.
            ScheduleStatus = new ScheduleStatus
            {
                Last        = adjustedInvocationTime,
                Next        = _schedule.GetNextOccurrence(adjustedInvocationTime),
                LastUpdated = adjustedInvocationTime
            };

            if (ScheduleMonitor != null)
            {
                await ScheduleMonitor.UpdateStatusAsync(_timerName, ScheduleStatus);

                _logger.LogDebug($"Function '{_timerName}' updated status: Last='{ScheduleStatus.Last.ToString("o")}', Next='{ScheduleStatus.Next.ToString("o")}', LastUpdated='{ScheduleStatus.LastUpdated.ToString("o")}'");
            }
        }
Example #19
0
 public void Start()
 {
     if (this.Scheduler.InStandbyMode || !this.Scheduler.IsStarted)
     {
         this.Scheduler.Start();
         this.Scheduler.Clear();
         this.GetScheduleStatus = ScheduleStatus.Starting;
     }
 }
Example #20
0
 public void Stop()
 {
     if (this.Scheduler.IsStarted)
     {
         this.Scheduler.Standby();
         QuartzTaskList.Clear();
         //QuartzModelList.Clear();
         this.GetScheduleStatus = ScheduleStatus.Stop;
     }
 }
Example #21
0
 /// <summary>
 /// Initializes a new instance of the BackupSchedule class.
 /// </summary>
 /// <param name="scheduleRecurrence">The schedule recurrence.</param>
 /// <param name="backupType">The type of backup which needs to be
 /// taken. Possible values include: 'LocalSnapshot',
 /// 'CloudSnapshot'</param>
 /// <param name="retentionCount">The number of backups to be
 /// retained.</param>
 /// <param name="startTime">The start time of the schedule.</param>
 /// <param name="scheduleStatus">The schedule status. Possible values
 /// include: 'Enabled', 'Disabled'</param>
 /// <param name="id">The path ID that uniquely identifies the
 /// object.</param>
 /// <param name="name">The name of the object.</param>
 /// <param name="type">The hierarchical type of the object.</param>
 /// <param name="kind">The Kind of the object. Currently only
 /// Series8000 is supported. Possible values include:
 /// 'Series8000'</param>
 /// <param name="lastSuccessfulRun">The last successful backup run
 /// which was triggered for the schedule.</param>
 public BackupSchedule(ScheduleRecurrence scheduleRecurrence, BackupType backupType, long retentionCount, System.DateTime startTime, ScheduleStatus scheduleStatus, string id = default(string), string name = default(string), string type = default(string), Kind?kind = default(Kind?), System.DateTime?lastSuccessfulRun = default(System.DateTime?))
     : base(id, name, type, kind)
 {
     ScheduleRecurrence = scheduleRecurrence;
     BackupType         = backupType;
     RetentionCount     = retentionCount;
     StartTime          = startTime;
     ScheduleStatus     = scheduleStatus;
     LastSuccessfulRun  = lastSuccessfulRun;
 }
Example #22
0
        public List <ScheduleStatus> ListScheduleStatuses()
        {
            ScheduleStatus emptyScheduleStatus = new ScheduleStatus();

            emptyScheduleStatus.ScheduleStatusId   = 0;
            emptyScheduleStatus.ScheduleStatusName = "Select Schedule Status";
            List <ScheduleStatus> listScheduleStatus = repository.ScheduleStatuses.OrderBy(x => x.ScheduleStatusName).ToList();

            listScheduleStatus.Insert(0, emptyScheduleStatus);
            return(listScheduleStatus);
        }
        public async Task StartAsync(CancellationToken cancellationToken)
        {
            ThrowIfDisposed();

            if (_timer != null && _timer.Enabled)
            {
                throw new InvalidOperationException("The listener has already been started.");
            }

            // if schedule monitoring is enabled, record (or initialize)
            // the current schedule status
            bool isPastDue = false;
            DateTime now = DateTime.Now;
            if (ScheduleMonitor != null)
            {
                // check to see if we've missed an occurrence since we last started.
                // If we have, invoke it immediately.
                _scheduleStatus = await ScheduleMonitor.GetStatusAsync(_timerName);
                TimeSpan pastDueDuration = await ScheduleMonitor.CheckPastDueAsync(_timerName, now, _schedule, _scheduleStatus);
                isPastDue = pastDueDuration != TimeSpan.Zero;

                if (_scheduleStatus == null)
                {
                    // no schedule status has been stored yet, so initialize
                    _scheduleStatus = new ScheduleStatus
                    {
                        Last = default(DateTime),
                        Next = _schedule.GetNextOccurrence(now)
                    };
                }
            }

            if (isPastDue)
            {
                _trace.Verbose(string.Format("Function '{0}' is past due on startup. Executing now.", _timerName));
                await InvokeJobFunction(now, true);
            }
            else if (_attribute.RunOnStartup)
            {
                // The job is configured to run immediately on startup
                _trace.Verbose(string.Format("Function '{0}' is configured to run on startup. Executing now.", _timerName));
                await InvokeJobFunction(now);
            }

            // log the next several occurrences to console for visibility
            string nextOccurrences = TimerInfo.FormatNextOccurrences(_schedule, 5);
            _trace.Verbose(nextOccurrences);

            // start the timer
            now = DateTime.Now;
            DateTime nextOccurrence = _schedule.GetNextOccurrence(now);
            TimeSpan nextInterval = nextOccurrence - now;
            StartTimer(nextInterval);
        }
        public async Task Listener_LogsInitialStatus_WhenUsingMonitor()
        {
            var status = new ScheduleStatus
            {
                Last = new DateTime(2016, 3, 4),
                Next = new DateTime(2016, 3, 4, 0, 0, 1)
            };

            var expected = $"Function 'Program.TestTimerJob' initial status: Last='{status.Last.ToString("o")}', Next='{status.Next.ToString("o")}'";

            await RunInitialStatusTestAsync(status, expected);
        }
Example #25
0
        public void ScheduleStatus_ReturnsExpectedValue()
        {
            TimerSchedule schedule  = new ConstantSchedule(TimeSpan.FromDays(1));
            TimerInfo     timerInfo = new TimerInfo(schedule, null);

            Assert.Null(timerInfo.ScheduleStatus);

            ScheduleStatus scheduleStatus = new ScheduleStatus();

            timerInfo = new TimerInfo(schedule, scheduleStatus);
            Assert.Same(scheduleStatus, timerInfo.ScheduleStatus);
        }
Example #26
0
        internal static string ToSerializedValue(this ScheduleStatus value)
        {
            switch (value)
            {
            case ScheduleStatus.Enabled:
                return("Enabled");

            case ScheduleStatus.Disabled:
                return("Disabled");
            }
            return(null);
        }
        public ActionResult Create()
        {
            ViewBag.Title = "Создание расписания";
            ViewBag.IsNew = true;
            var schedule = new Schedule {/*BeginDate = DateTime.Today*/
            };

            //ViewBag.PatientCode_Data = new SelectList(DataProvider.GetList(new PatientDataFilter()), "Id", "FullName");
            ViewBag.TrialCenterID_Data = new SelectList(DataProvider.GetList(new TrialCenterDataFilter()), "Id", "Number");
            ViewBag.ScheduleStatuses   = ScheduleStatus.GetScheduleStatuses();
            return(View(schedule));
        }
        public async Task Listener_LogsInitialStatus_WhenUsingMonitor()
        {
            var status = new ScheduleStatus
            {
                Last        = new DateTime(2016, 3, 4),
                Next        = new DateTime(2016, 3, 4, 0, 0, 1),
                LastUpdated = new DateTime(2016, 3, 3, 23, 59, 59)
            };

            var expected = $"Function '{_functionShortName}' initial status: Last='{status.Last.ToString("o")}', Next='{status.Next.ToString("o")}', LastUpdated='{status.LastUpdated.ToString("o")}'";

            await RunInitialStatusTestAsync(status, expected);
        }
        public async Task CheckPastDueAsync_ScheduleUpdate_UpdatesStatusFile()
        {
            Mock <TimerSchedule> mockSchedule = new Mock <TimerSchedule>(MockBehavior.Strict);
            DateTime             now          = DateTime.Now;
            DateTime             next         = now + TimeSpan.FromDays(2);
            ScheduleStatus       status       = new ScheduleStatus
            {
                Last        = now,
                Next        = next,
                LastUpdated = now
            };
            await _monitor.UpdateStatusAsync(_testTimerName, status);

            mockSchedule.Setup(p => p.GetNextOccurrence(It.IsAny <DateTime>())).Returns(next);
            TimeSpan pastDueAmount = await _monitor.CheckPastDueAsync(_testTimerName, now, mockSchedule.Object, status);

            Assert.Equal(TimeSpan.Zero, pastDueAmount);

            // now adjust the schedule
            DateTime adjustedNext = next - TimeSpan.FromDays(1);

            mockSchedule.Setup(p => p.GetNextOccurrence(It.IsAny <DateTime>())).Returns(adjustedNext);
            pastDueAmount = await _monitor.CheckPastDueAsync(_testTimerName, now, mockSchedule.Object, status);

            Assert.Equal(TimeSpan.Zero, pastDueAmount);
            ScheduleStatus updatedStatus = await _monitor.GetStatusAsync(_testTimerName);

            Assert.Equal(default(DateTime), updatedStatus.Last);
            Assert.Equal(adjustedNext, updatedStatus.Next);
            Assert.Equal(now, updatedStatus.LastUpdated);

            now           = now + TimeSpan.FromHours(23);
            pastDueAmount = await _monitor.CheckPastDueAsync(_testTimerName, now, mockSchedule.Object, status);

            Assert.Equal(TimeSpan.Zero, pastDueAmount);

            now           = now + TimeSpan.FromHours(1);
            pastDueAmount = await _monitor.CheckPastDueAsync(_testTimerName, now, mockSchedule.Object, status);

            Assert.Equal(TimeSpan.Zero, pastDueAmount);

            now           = now + TimeSpan.FromHours(1);
            pastDueAmount = await _monitor.CheckPastDueAsync(_testTimerName, now, mockSchedule.Object, status);

            Assert.Equal(TimeSpan.FromHours(1), pastDueAmount);
        }
        public async Task StartAsync_SchedulePastDue_InvokesJobFunctionImmediately()
        {
            // Set this to true to ensure that the function is only executed once
            // In this case, because it is run on startup due to being behind schedule,
            // it shouldn't be run twice.
            _attribute.RunOnStartup = true;

            ScheduleStatus status = new ScheduleStatus();

            _mockScheduleMonitor.Setup(p => p.GetStatusAsync(_testTimerName)).ReturnsAsync(status);

            DateTime lastOccurrence = default(DateTime);
            TimeSpan pastDueAmount  = TimeSpan.FromMinutes(3);

            _mockScheduleMonitor.Setup(p => p.CheckPastDueAsync(_testTimerName, It.IsAny <DateTime>(), It.IsAny <TimerSchedule>(), status))
            .Callback <string, DateTime, TimerSchedule, ScheduleStatus>((mockTimerName, mockNow, mockNext, mockStatus) =>
            {
                lastOccurrence = mockNow;
            })
            .ReturnsAsync(pastDueAmount);

            _mockScheduleMonitor.Setup(p => p.UpdateStatusAsync(_testTimerName, It.IsAny <ScheduleStatus>()))
            .Callback <string, ScheduleStatus>((mockTimerName, mockStatus) =>
            {
                Assert.Equal(lastOccurrence, mockStatus.Last);
                DateTime expectedNextOccurrence = _schedule.GetNextOccurrence(lastOccurrence);
                Assert.Equal(expectedNextOccurrence, mockStatus.Next);
            })
            .Returns(Task.FromResult(true));

            CancellationToken cancellationToken = CancellationToken.None;
            await _listener.StartAsync(cancellationToken);

            TimerInfo timerInfo = (TimerInfo)_triggeredFunctionData.TriggerValue;

            Assert.Same(status, timerInfo.ScheduleStatus);
            Assert.True(timerInfo.IsPastDue);

            _mockTriggerExecutor.Verify(p => p.TryExecuteAsync(It.IsAny <TriggeredFunctionData>(), It.IsAny <CancellationToken>()), Times.Once());

            // Make sure we've added the reason for the invocation into the Details
            Assert.Equal(default(DateTime).ToString("o"), _triggeredFunctionData.TriggerDetails[TimerListener.OriginalScheduleKey]);
            Assert.Equal("IsPastDue", _triggeredFunctionData.TriggerDetails[TimerListener.UnscheduledInvocationReasonKey]);

            _listener.Dispose();
        }
Example #31
0
        public async Task RunInitialStatusTestAsync(ScheduleStatus initialStatus, string expected)
        {
            _mockScheduleMonitor
            .Setup(m => m.GetStatusAsync(_testTimerName))
            .ReturnsAsync(initialStatus);
            _mockScheduleMonitor
            .Setup(m => m.CheckPastDueAsync(_testTimerName, It.IsAny <DateTime>(), _schedule, It.IsAny <ScheduleStatus>()))
            .ReturnsAsync(TimeSpan.Zero);

            await _listener.StartAsync(CancellationToken.None);

            await _listener.StopAsync(CancellationToken.None);

            _listener.Dispose();

            Assert.Equal(expected, _logger.LogMessages.Single(m => m.Level == LogLevel.Debug).FormattedMessage);
        }
 public static void SetScheduleStatus(ScheduleStatus newStatus)
 {
     try
     {
         //note:locking inside this method is highly misleading
         //as there is no lock in place between when the caller
         //decides to call this method and when the lock is acquired
         //the value could easily change in that time
         StatusLock.AcquireWriterLock(LockTimeout);
         try
         {
             // It is safe for this thread to read or write
             // from the shared resource.
             _status = newStatus;
         }
         finally
         {
             // Ensure that the lock is released.
             StatusLock.ReleaseWriterLock();
         }
     }
     catch (ApplicationException ex)
     {
         // The writer lock request timed out.
         Interlocked.Increment(ref _writerTimeouts);
         Exceptions.Exceptions.LogException(ex);
     }
 }
		private void BindStatus()
		{
			Status = SchedulingProvider.Instance().GetScheduleStatus();
			lblStatus.Text = Status.ToString();

			placeCommands.Visible = SchedulingProvider.SchedulerMode == SchedulerMode.TIMER_METHOD;

			if (Status == ScheduleStatus.STOPPED && SchedulingProvider.SchedulerMode != SchedulerMode.DISABLED)
			{
				cmdStart.Enabled = true;
				cmdStop.Enabled = false;
			}
			else if (Status == ScheduleStatus.WAITING_FOR_REQUEST || SchedulingProvider.SchedulerMode == SchedulerMode.DISABLED)
			{
				cmdStart.Enabled = false;
				cmdStop.Enabled = false;
			}
			else
			{
				cmdStart.Enabled = false;
				cmdStop.Enabled = true;
			}
		}
        public static void SetScheduleStatus(ScheduleStatus newStatus)
        {
            try
            {

                StatusLock.AcquireWriterLock(LockTimeout);
                try
                {
                    _status = newStatus;
                }
                finally
                {
                    StatusLock.ReleaseWriterLock();
                }
            }
            catch (ApplicationException ex)
            {
                Interlocked.Increment(ref _writerTimeouts);
                ErrorLogger.SchedulerProcessException(ex);
            }
        }
Example #35
0
            public CoreScheduler( bool boolDebug, int MaxThreads )
            {
                Status = ScheduleStatus.STOPPED;

                Debug = boolDebug;
                if( ! ThreadPoolInitialized )
                {
                    InitializeThreadPool( MaxThreads );
                }
            }
        internal async Task InvokeJobFunction(DateTime lastOccurrence, bool isPastDue = false)
        {
            CancellationToken token = _cancellationTokenSource.Token;
            TimerInfo timerInfo = new TimerInfo(_attribute.Schedule, _scheduleStatus, isPastDue);
            TriggeredFunctionData input = new TriggeredFunctionData
            {
                TriggerValue = timerInfo
            };

            try
            {
                FunctionResult result = await _executor.TryExecuteAsync(input, token);
                if (!result.Succeeded)
                {
                    token.ThrowIfCancellationRequested();
                }
            }
            catch
            {
                // We don't want any function errors to stop the execution
                // schedule. Errors will be logged to Dashboard already.
            }

            if (ScheduleMonitor != null)
            {
                _scheduleStatus = new ScheduleStatus
                {
                    Last = lastOccurrence,
                    Next = _schedule.GetNextOccurrence(lastOccurrence)
                };
                await ScheduleMonitor.UpdateStatusAsync(_timerName, _scheduleStatus);
            }
        }
Example #37
0
 public static void SetScheduleStatus( ScheduleStatus objScheduleStatus )
 {
     try
     {
         objStatusReadWriteLock.AcquireWriterLock( WriteTimeout );
         try
         {
             // It is safe for this thread to read or write
             // from the shared resource.
             Status = objScheduleStatus;
             Interlocked.Increment( ref Writes );
         }
         finally
         {
             // Ensure that the lock is released.
             objStatusReadWriteLock.ReleaseWriterLock();
         }
     }
     catch( ApplicationException ex )
     {
         // The writer lock request timed out.
         Interlocked.Increment( ref WriterTimeouts );
         Exceptions.Exceptions.LogException( ex );
     }
 }
Example #38
0
            public CoreScheduler( int MaxThreads )
            {
                Status = ScheduleStatus.STOPPED;

                if( ! ThreadPoolInitialized )
                {
                    InitializeThreadPool( MaxThreads );
                }
            }
Example #39
0
 /// <summary>
 /// This must run under the lock!
 /// </summary>
 private bool? TryGetTaskToRun(ref AbstractTask task)
 {
     //this approach gives us an O(1) _removal_ cost from the list
     LinkedListNode<SchedulePair> node = CurrentThreadQueuedTasks.First;
     while (node != null)
     {
         SchedulePair pair = node.Value;
         if (pair.Condition())
         {
             task = pair.Task;
             CurrentThreadQueuedTasks.Remove(node);
             break;
         }
         pair.CannotRunCount += 1;
         //this is probably a process that is waiting for other processes
         //move it to the end of the list so we don't have to iterate over it all
         //the time
         LinkedListNode<SchedulePair> prev = node;
         node = node.Next;
         if (pair.CannotRunCount == 3 && Status != ScheduleStatus.Idle)
         {
             pair.CannotRunCount = -1; //give it a bit of a boost for the next time
             CurrentThreadQueuedTasks.Remove(prev);
             CurrentThreadQueuedTasks.AddLast(prev);
         }
     }
     if (task == null) // no tasks to run in the curren threa, time to steal some work...
     {
         StealWorkFromAnotherThread();
         //nothing runs, and there are no tasks that we _can_ run
         // we are either deadlocked or waiting for an external resource
         // we will let the idle task decide what to do.
         if (currentRunningProcessCount == 0)
         {
             Status = ScheduleStatus.Idle;
             task = idleTask;
             return true;
         }
     }
     return null;
 }