Example #1
0
 TaskExecution(IBackgourndTask backgroundTask)
 {
     BackgroundTask          = backgroundTask;
     CancellationTokenSource = new CancellationTokenSource();
     CancellationToken       = CancellationTokenSource.Token;
     HeartbeatTask           = CreateHeartbeatTask();
 }
Example #2
0
 internal static async Task Run(IBackgourndTask task)
 {
     using (var runner = new TaskExecution(task))
     {
         await runner.DoRun();
     }
 }
Example #3
0
        static async Task Run(this IBackgourndTask task)
        {
            var start = LocalTime.Now;

            Log.Info($"Running background task '{task.Name}'");
            await Db.Update(task, x =>
            {
                x.Heartbeat         = LocalTime.UtcNow;
                x.ExecutingInstance = Engine.ExecutionId;
            }).ConfigureAwait(false);

            try
            {
                await Engine.GetAction(task).ConfigureAwait(false);

                Log.Info($"Sucessfully ran background task '{task.Name}' in {LocalTime.Now.Subtract(start).ToNaturalTime()}");
            }
            catch (Exception ex)
            {
                Log.Error(ex, $"Failed to run background task '{task.Name}' because: " + ex.ToFullMessage());
            }
            finally
            {
                await Db.Update(await Db.Reload(task), t =>
                {
                    t.LastExecuted      = LocalTime.Now;
                    t.ExecutingInstance = null;
                    t.Heartbeat         = null;
                }).ConfigureAwait(false);
            }
        }
Example #4
0
        static bool ShouldRun(IBackgourndTask task)
        {
            var nextExecution = task.LastExecuted.GetValueOrDefault().AddMinutes(task.IntervalInMinutes);

            if (nextExecution.IsInTheFuture())
            {
                return(false);
            }

            Log.Info($"{task.Name} is due.");

            if (task.Heartbeat is null)
            {
                return(true);
            }

            if (task.Heartbeat.Value.AddMinutes(task.TimeoutInMinutes) > LocalTime.UtcNow)
            {
                Log.Info($"Skipped due background task '{task.Name}' because last attempt is still running on [{task.ExecutingInstance}] instance.");
                return(false);
            }

            Log.Info($"Last attempt to run the background task '{task.Name}' on [{task.ExecutingInstance}] timed out.");
            return(true);
        }
Example #5
0
        static async Task <IBackgourndTask> Update(IBackgourndTask task, Action <IBackgourndTask> action)
        {
            var clone = (IBackgourndTask)(await Database.Reload(task)).Clone();

            action(clone);

            clone = await Database.Save(clone);

            return(await Database.Reload(clone));
        }
Example #6
0
        internal static Task <IBackgourndTask> SendHeartbeat(this IBackgourndTask task)
        {
            task.Logger().Info("Recording heartbeat for " + task.Name);

            return(Update(task, t =>
            {
                t.Heartbeat = LocalTime.Now;
                t.ExecutingInstance = ExecutionEngine.Id;
            }));
        }
Example #7
0
 internal static Task RecordExecution(this IBackgourndTask task)
 {
     task.Logger().Info("Recording execution for " + task.Name);
     return(Update(task, t =>
     {
         t.LastExecuted = LocalTime.Now;
         t.ExecutingInstance = null;
         t.Heartbeat = null;
     }));
 }
Example #8
0
        internal static async Task <bool> TryPick(this IBackgourndTask task)
        {
            var result = false;

            LogInfo($"Checking to see if {task.Name} has to run.");
            using (var scope = Database.CreateTransactionScope())
            {
                LogInfo($"Causing a distributed lock for {task.Name}.");
                // cause a distributed lock
                await DataAccess.Create().ExecuteNonQuery($"update {task.GetType().Name.ToPlural()} set Heartbeat = Heartbeat where Name = '{task.Name}'");

                task = await Database.Reload(task);

                var lastExecuted  = task.LastExecuted.GetValueOrDefault();
                var nextExecution = lastExecuted.AddMinutes(task.IntervalInMinutes);

                if (nextExecution.IsInTheFuture())
                {
                    LogInfo($"Should still wait for running [{task.Name}]. Next execution is at {nextExecution}.");
                    result = false;
                }
                else
                {
                    LogInfo($"{task.Name} should run.");
                    var lastHeartbeat = task.Heartbeat.GetValueOrDefault();
                    var stillAlive    = lastHeartbeat.AddMinutes(task.TimeoutInMinutes).IsInTheFuture();

                    if (stillAlive)
                    {
                        LogInfo($"[{task.Name}] is already running on [{task.ExecutingInstance}] instance.");
                    }
                    else
                    {
                        LogInfo($"[{task.Name}] is not running. Last heartbeat : " + lastHeartbeat);
                        await task.SendHeartbeat();
                    }

                    result = !stillAlive;
                }

                scope.Complete();

                return(result);
            }
        }
Example #9
0
        private Task CreateHeartbeatTask()
        {
            return(Task.Run(async() =>
            {
                while (!CancellationToken.IsCancellationRequested)
                {
                    try
                    {
                        BackgroundTask = await BackgroundTask.SendHeartbeat();
                    }
                    catch (Exception ex)
                    {
                        Log.For(this).Error(ex, "Failed to log heartbeat because : " + ex.ToFullMessage());
                    }

                    await Task.Delay(HEARTBEAT_DELAY);
                }
            }, CancellationToken));
        }
Example #10
0
        private Task CreateHeartbeatTask()
        {
            return(Task.Run(async() =>
            {
                while (true)
                {
                    if (CancellationToken.IsCancellationRequested)
                    {
                        return;
                    }
                    try
                    {
                        BackgroundTask = await BackgroundTask.SendHeartbeat();
                    }
                    catch (Exception ex)
                    {
                        Log.For(this).Error(ex, "Failed to log heartbeat.");
                    }

                    await Task.Delay(HEARTBEAT_DELAY);
                }
            }, CancellationToken));
        }
Example #11
0
 internal static Task GetActionTask(this IBackgourndTask task) =>
 BackgroundProcessManager.Current.GetAction(task);
Example #12
0
 internal static Task GetAction(IBackgourndTask task) => Actions[task.Name]();