public ScheduledTaskAsyncCallback Wrap(ScheduledTaskCallback callback, Func<ScheduledTask, DateTimeOffset, bool> shouldTryToRun = null)
        {
            if (callback == null)
                throw new ArgumentNullException(nameof(callback));

            return GetWrappedCallback(callback, null, shouldTryToRun);
        }
Example #2
0
        public ScheduledTask AddScheduledTask(double interval, ScheduledTaskCallback callback)
        {
            ScheduledTask task = new ScheduledTask();

            task.Interval = interval; task.Callback = callback;
            Tasks.Add(task);
            return(task);
        }
Example #3
0
        public ScheduledTaskAsyncCallback Wrap(ScheduledTaskCallback callback, Func <ScheduledTask, DateTimeOffset, bool> shouldTryToRun = null)
        {
            if (callback == null)
            {
                throw new ArgumentNullException(nameof(callback));
            }

            return(GetWrappedCallback(callback, null, shouldTryToRun));
        }
Example #4
0
        private static ScheduledTask[] AddTaskMulti(string name, string schedule, Combo[] combos, ScheduledTaskCallback callback)
        {
            var tasks = new ScheduledTask[combos.Length];
            for (var i = 0; i < combos.Length; i++)
            {
                var schtick = combos[i].Schtick;
                var wrapper = combos[i].Wrapper;
                tasks[i] = schtick.AddAsyncTask(name, schedule, wrapper.Wrap(callback));
            }

            return tasks;
        }
Example #5
0
        ScheduledTask AddTaskImpl(
            string name,
            Schedule schedule,
            ScheduledTaskCallback callback,
            ScheduledTaskAsyncCallback asyncCallback,
            bool autoRun,
            DateTimeOffset lastKnownEvent,
            TimeSpan window)
        {
            if (schedule == null)
            {
                throw new ArgumentNullException(nameof(schedule));
            }

            if (name == null)
            {
                name = Guid.NewGuid().ToString();
            }

            ScheduledTask task;

            lock (_lockTasks)
            {
                if (IsShuttingDown)
                {
                    throw new Exception("Cannot add a task to Schtick after Shutdown() has been called.");
                }

                if (_tasks.ContainsKey(name))
                {
                    throw new Exception($"A scheduled task named \"{name}\" already exists.");
                }

                task = new ScheduledTask(this, name, schedule, callback, asyncCallback)
                {
                    Window     = window,
                    IsAttached = true,
                };

                _tasks.Add(name, task);
            }

            task.OnException += TaskOnOnException;

            if (autoRun)
            {
                task.StartSchedule(lastKnownEvent);
            }

            return(task);
        }
Example #6
0
        internal ScheduledTask(Schtick schtick, string name, Schedule schedule, ScheduledTaskCallback callback, ScheduledTaskAsyncCallback asyncCallback)
        {
            _schtick = schtick;
            Name     = name;
            Schedule = schedule;

            if ((callback == null) == (asyncCallback == null))
            {
                throw new Exception("callback or asyncCallback must be specified, but not both.");
            }

            Callback      = callback;
            AsyncCallback = asyncCallback;
        }
Example #7
0
        /// <summary>
        /// Adds a scheduled task to this instance of Schtick.
        /// </summary>
        /// <param name="name">A unique name for this task. If null, a guid will be used.</param>
        /// <param name="schedule">A Schyntax Schedule object.</param>
        /// <param name="callback">Function which will be called each time the task is supposed to run.</param>
        /// <param name="autoRun">If true, Start() will be called on the task automatically.</param>
        /// <param name="lastKnownEvent">The last Date when the task is known to have run. Used for Task Windows.</param>
        /// <param name="window">
        /// The period of time after an event should have run where it would still be appropriate to run it.
        /// See Task Windows documentation for more details.
        /// </param>
        public ScheduledTask AddTask(
            string name,
            Schedule schedule,
            ScheduledTaskCallback callback,
            bool autoRun = true,
            DateTimeOffset lastKnownEvent = default(DateTimeOffset),
            TimeSpan window = default(TimeSpan))
        {
            if (callback == null)
            {
                throw new ArgumentNullException(nameof(callback));
            }

            return(AddTaskImpl(name, schedule, callback, null, autoRun, lastKnownEvent, window));
        }
Example #8
0
        /// <summary>
        /// Adds a scheduled task to this instance of Schtick.
        /// </summary>
        /// <param name="name">A unique name for this task. If null, a guid will be used.</param>
        /// <param name="schedule">A Schyntax schedule string.</param>
        /// <param name="callback">Function which will be called each time the task is supposed to run.</param>
        /// <param name="autoRun">If true, Start() will be called on the task automatically.</param>
        /// <param name="lastKnownEvent">The last Date when the task is known to have run. Used for Task Windows.</param>
        /// <param name="window">
        /// The period of time after an event should have run where it would still be appropriate to run it.
        /// See Task Windows documentation for more details.
        /// </param>
        public ScheduledTask AddTask(
            string name,
            string schedule,
            ScheduledTaskCallback callback,
            bool autoRun = true,
            DateTimeOffset lastKnownEvent = default(DateTimeOffset),
            TimeSpan window = default(TimeSpan))
        {
            if (schedule == null)
                throw new ArgumentNullException(nameof(schedule));

            if (callback == null)
                throw new ArgumentNullException(nameof(callback));

            return AddTaskImpl(name, new Schedule(schedule), callback, null, autoRun, lastKnownEvent, window);
        }
Example #9
0
        private ScheduledTaskAsyncCallback GetWrappedCallback(
            ScheduledTaskCallback originalCallback,
            ScheduledTaskAsyncCallback originalAsyncCallback,
            Func <ScheduledTask, DateTimeOffset, bool> shouldTryToRun)
        {
            var host    = _machineName;
            var lastKey = _lastKey;

            return(async(task, timeIntendedToRun) =>
            {
                if (shouldTryToRun?.Invoke(task, timeIntendedToRun) == false)
                {
                    return;
                }

                var iso = timeIntendedToRun.ToString("o");
                RedisKey lockKey = _keyPrefix + ";" + task.Name + ";" + iso;
                var lastLockValue = iso + ";" + DateTimeOffset.UtcNow.ToString("o") + ";" + host;

                // set the redis lock for one hour longer than the window
                var window = task.Window;
                var expiry = (window > TimeSpan.Zero ? window : TimeSpan.Zero) + TimeSpan.FromHours(1);
                var px = expiry.TotalMilliseconds;

                // see if we can get the lock on this task
                var db = _getRedisDb();
                var name = task.Name;
                var lockAcquired = await db.ScriptEvaluateAsync(
                    s_redisLockScript,
                    new { lockKey, host, px, lastKey, name, lastLockValue },
                    flags : CommandFlags.DemandMaster
                    ).ConfigureAwait(false);

                if ((int)lockAcquired == 1)
                {
                    // we got the lock, now run the task
                    if (originalCallback != null)
                    {
                        originalCallback(task, timeIntendedToRun);
                    }
                    else
                    {
                        await originalAsyncCallback(task, timeIntendedToRun).ConfigureAwait(false);
                    }
                }
            });
        }
Example #10
0
        private static ScheduledTask[] AddTaskMulti(string name, string schedule, Combo[] combos, ScheduledTaskCallback callback)
        {
            var tasks = new ScheduledTask[combos.Length];

            for (var i = 0; i < combos.Length; i++)
            {
                var schtick = combos[i].Schtick;
                var wrapper = combos[i].Wrapper;
                tasks[i] = schtick.AddAsyncTask(name, schedule, wrapper.Wrap(callback));
            }

            return(tasks);
        }
Example #11
0
        internal ScheduledTask(Schtick schtick, string name, Schedule schedule, ScheduledTaskCallback callback, ScheduledTaskAsyncCallback asyncCallback)
        {
            _schtick = schtick;
            Name = name;
            Schedule = schedule;

            if ((callback == null) == (asyncCallback == null))
                throw new Exception("callback or asyncCallback must be specified, but not both.");

            Callback = callback;
            AsyncCallback = asyncCallback;
        }
Example #12
0
        private ScheduledTask AddTaskImpl(
            string name,
            Schedule schedule,
            ScheduledTaskCallback callback,
            ScheduledTaskAsyncCallback asyncCallback,
            bool autoRun,
            DateTimeOffset lastKnownEvent,
            TimeSpan window)
        {
            if (schedule == null)
                throw new ArgumentNullException(nameof(schedule));

            if (name == null)
                name = Guid.NewGuid().ToString();
            
            ScheduledTask task;
            lock (_lockTasks)
            {
                if (IsShuttingDown)
                    throw new Exception("Cannot add a task to Schtick after Shutdown() has been called.");

                if (_tasks.ContainsKey(name))
                    throw new Exception($"A scheduled task named \"{name}\" already exists.");

                task = new ScheduledTask(this, name, schedule, callback, asyncCallback)
                {
                    Window = window,
                    IsAttached = true,
                };

                _tasks.Add(name, task);
            }

            task.OnException += TaskOnOnException;

            if (autoRun)
                task.StartSchedule(lastKnownEvent);

            return task;
        }
        private ScheduledTaskAsyncCallback GetWrappedCallback(
            ScheduledTaskCallback originalCallback, 
            ScheduledTaskAsyncCallback originalAsyncCallback, 
            Func<ScheduledTask, DateTimeOffset, bool> shouldTryToRun)
        {
            var host = _machineName;
            var lastKey = _lastKey;

            return async (task, timeIntendedToRun) =>
            {
                if (shouldTryToRun?.Invoke(task, timeIntendedToRun) == false)
                    return;

                var iso = timeIntendedToRun.ToString("o");
                RedisKey lockKey = _keyPrefix + ";" + task.Name + ";" + iso;
                var lastLockValue = iso + ";" + DateTimeOffset.UtcNow.ToString("o") + ";" + host;

                // set the redis lock for one hour longer than the window
                var window = task.Window;
                var expiry = (window > TimeSpan.Zero ? window : TimeSpan.Zero) + TimeSpan.FromHours(1);
                var px = expiry.TotalMilliseconds;

                // see if we can get the lock on this task
                var db = _getRedisDb();
                var name = task.Name;
                var lockAcquired = await db.ScriptEvaluateAsync(
                    s_redisLockScript,
                    new { lockKey, host, px, lastKey, name, lastLockValue },
                    flags: CommandFlags.DemandMaster
                ).ConfigureAwait(false);

                if ((int)lockAcquired == 1)
                {
                    // we got the lock, now run the task
                    if (originalCallback != null)
                        originalCallback(task, timeIntendedToRun);
                    else
                        await originalAsyncCallback(task, timeIntendedToRun).ConfigureAwait(false);
                }
            };
        }