<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Signum.Engine.Maps;
using Signum.Entities.Scheduler;
using Signum.Engine.Basics;
using Signum.Utilities;
using Signum.Utilities.DataStructures;
using Signum.Engine.Operations;
using Signum.Entities;
using System.Threading;
using Signum.Engine.Processes;
using Signum.Entities.Processes;
using Signum.Engine.Authorization;
using Signum.Engine.DynamicQuery;
using System.Reflection;
using System.Threading.Tasks;
using Signum.Entities.Authorization;
using System.Linq.Expressions;
using Signum.Engine.Cache;
using Signum.Entities.Basics;
using Signum.Utilities.ExpressionTrees;
using Signum.Entities.Isolation;

namespace Signum.Engine.Scheduler
{
    public static class SchedulerLogic
    {
        public static Func<ITaskEntity, ScheduledTaskEntity, IDisposable> ApplySession;

        static Expression<Func<ITaskEntity, IQueryable<ScheduledTaskLogEntity>>> ExecutionsExpression =
         ct => Database.Query<ScheduledTaskLogEntity>().Where(a => a.Task == ct);
        public static IQueryable<ScheduledTaskLogEntity> Executions(this ITaskEntity e)
        {
            return ExecutionsExpression.Evaluate(e);
        }

        static Expression<Func<ITaskEntity, ScheduledTaskLogEntity>> LastExecutionExpression =
            e => e.Executions().OrderByDescending(a => a.StartTime).FirstOrDefault();
        public static ScheduledTaskLogEntity LastExecution(this ITaskEntity e)
        {
            return LastExecutionExpression.Evaluate(e);
        }

        static Expression<Func<ScheduledTaskEntity, IQueryable<ScheduledTaskLogEntity>>> ExecutionsSTExpression =
            ct => Database.Query<ScheduledTaskLogEntity>().Where(a => a.ScheduledTask == ct);
        [ExpressionField("ExecutionsSTExpression")]
        public static IQueryable<ScheduledTaskLogEntity> Executions(this ScheduledTaskEntity e)
        {
            return ExecutionsSTExpression.Evaluate(e);
        }

        public static Polymorphic<Func<ITaskEntity, Lite<IEntity>>> ExecuteTask = new Polymorphic<Func<ITaskEntity, Lite<IEntity>>>();

        public class ScheduledTaskPair
        {
            public ScheduledTaskEntity ScheduledTask;
            public DateTime NextDate;
        }

        static ResetLazy<List<ScheduledTaskEntity>> ScheduledTasksLazy;

        static PriorityQueue<ScheduledTaskPair> priorityQueue = new PriorityQueue<ScheduledTaskPair>((a, b) => a.NextDate.CompareTo(b.NextDate));

        static Timer timer = new Timer(new TimerCallback(TimerCallback), // main timer
                                null,
                                Timeout.Infinite,
                                Timeout.Infinite);


        public static void Start(SchemaBuilder sb, DynamicQueryManager dqm)
        {
            if (sb.NotDefined(MethodInfo.GetCurrentMethod()))
            {
                AuthLogic.AssertStarted(sb);
                OperationLogic.AssertStarted(sb);

                Implementations imp = sb.Settings.GetImplementations((ScheduledTaskEntity st) => st.Task);
                Implementations imp2 = sb.Settings.GetImplementations((ScheduledTaskLogEntity st) => st.Task);

                if (!imp2.Equals(imp2))
                    throw new InvalidOperationException("Implementations of ScheduledTaskEntity.Task should be the same as in ScheduledTaskLogEntity.Task");

                PermissionAuthLogic.RegisterPermissions(SchedulerPermission.ViewSchedulerPanel);

                ExecuteTask.Register((ITaskEntity t) => { throw new NotImplementedException("SchedulerLogic.ExecuteTask not registered for {0}".FormatWith(t.GetType().Name)); });

                SimpleTaskLogic.Start(sb, dqm);
                sb.Include<ScheduledTaskEntity>();
                sb.Include<ScheduledTaskLogEntity>();

                dqm.RegisterQuery(typeof(HolidayCalendarEntity), () =>
                     from st in Database.Query<HolidayCalendarEntity>()
                     select new
                     {
                         Entity = st,
                         st.Id,
                         st.Name,
                         Holidays = st.Holidays.Count,
                     });


                dqm.RegisterQuery(typeof(ScheduledTaskEntity), () =>
                    from st in Database.Query<ScheduledTaskEntity>()
                    select new
                    {
                        Entity = st,
                        st.Id,
                        st.Task,
                        st.Rule,
                        st.Suspended,
                        st.MachineName,
                        st.ApplicationName
                    });

                dqm.RegisterQuery(typeof(ScheduledTaskLogEntity), () =>
                    from cte in Database.Query<ScheduledTaskLogEntity>()
                    select new
                    {
                        Entity = cte,
                        cte.Id,
                        cte.Task,
                        cte.ScheduledTask,
                        cte.StartTime,
                        cte.EndTime,
                        cte.ProductEntity,
                        cte.MachineName,
                        cte.User,
                        cte.Exception,

                    });

                dqm.RegisterExpression((ITaskEntity ct) => ct.Executions(), () => TaskMessage.Executions.NiceToString());
                dqm.RegisterExpression((ITaskEntity ct) => ct.LastExecution(), () => TaskMessage.LastExecution.NiceToString());
                dqm.RegisterExpression((ScheduledTaskEntity ct) => ct.Executions(), () => TaskMessage.Executions.NiceToString());

                new Graph<HolidayCalendarEntity>.Execute(HolidayCalendarOperation.Save)
                {
                    AllowsNew = true,
                    Lite = false,
                    Execute = (c, _) => { },
                }.Register();

                new Graph<HolidayCalendarEntity>.Delete(HolidayCalendarOperation.Delete)
                {
                    Delete = (c, _) => { c.Delete(); },
                }.Register();

                new Graph<ScheduledTaskEntity>.Execute(ScheduledTaskOperation.Save)
                {
                    AllowsNew = true,
                    Lite = false,
                    Execute = (st, _) => { },
                }.Register();

                new Graph<ScheduledTaskEntity>.Delete(ScheduledTaskOperation.Delete)
                {
                    Delete = (st, _) =>
                    {
                        st.Executions().UnsafeUpdate().Set(l => l.ScheduledTask, l => null).Execute();
                        var rule = st.Rule; st.Delete(); rule.Delete();
                    },
                }.Register();


                new Graph<IEntity>.ConstructFrom<ITaskEntity>(TaskOperation.ExecuteSync)
                {
                    Construct = (task, _) => ExecuteSync(task, null, UserHolder.Current).Try(l => l.Retrieve())
                }.Register();

                new Graph<ITaskEntity>.Execute(TaskOperation.ExecuteAsync)
                {
                    Execute = (task, _) => ExecuteAsync(task, null, UserHolder.Current)
                }.Register();

                ScheduledTasksLazy = sb.GlobalLazy(() =>
                    Database.Query<ScheduledTaskEntity>().Where(a => !a.Suspended &&
                        (a.MachineName == ScheduledTaskEntity.None || a.MachineName == Environment.MachineName && a.ApplicationName == Schema.Current.ApplicationName)).ToList(),
                    new InvalidateWith(typeof(ScheduledTaskEntity)));

                ScheduledTasksLazy.OnReset += ScheduledTasksLazy_OnReset;

                ExceptionLogic.DeleteLogs += ExceptionLogic_DeleteLogs;
            }
        }

        public static void ExceptionLogic_DeleteLogs(DeleteLogParametersEntity parameters)
        {
            Database.Query<ScheduledTaskLogEntity>().Where(a => a.StartTime < parameters.DateLimit).UnsafeDeleteChunks(parameters.ChunkSize, parameters.MaxChunks);
        }

        static void ScheduledTasksLazy_OnReset(object sender, EventArgs e)
        {
            Task.Factory.StartNew(() => { Thread.Sleep(1000); ReloadPlan(); });
        }


        static bool running = false;
        public static bool Running
        {
            get { return running; }
        }

        public static void StartScheduledTasks()<commit_msg>Fix SchedulerLogic<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Signum.Engine.Maps;
using Signum.Entities.Scheduler;
using Signum.Engine.Basics;
using Signum.Utilities;
using Signum.Utilities.DataStructures;
using Signum.Engine.Operations;
using Signum.Entities;
using System.Threading;
using Signum.Engine.Processes;
using Signum.Entities.Processes;
using Signum.Engine.Authorization;
using Signum.Engine.DynamicQuery;
using System.Reflection;
using System.Threading.Tasks;
using Signum.Entities.Authorization;
using System.Linq.Expressions;
using Signum.Engine.Cache;
using Signum.Entities.Basics;
using Signum.Utilities.ExpressionTrees;
using Signum.Entities.Isolation;

namespace Signum.Engine.Scheduler
{
    public static class SchedulerLogic
    {
        public static Func<ITaskEntity, ScheduledTaskEntity, IDisposable> ApplySession;

        static Expression<Func<ITaskEntity, IQueryable<ScheduledTaskLogEntity>>> ExecutionsExpression =
         ct => Database.Query<ScheduledTaskLogEntity>().Where(a => a.Task == ct);
        public static IQueryable<ScheduledTaskLogEntity> Executions(this ITaskEntity e)
        {
            return ExecutionsExpression.Evaluate(e);
        }

        static Expression<Func<ITaskEntity, ScheduledTaskLogEntity>> LastExecutionExpression =
            e => e.Executions().OrderByDescending(a => a.StartTime).FirstOrDefault();
        public static ScheduledTaskLogEntity LastExecution(this ITaskEntity e)
        {
            return LastExecutionExpression.Evaluate(e);
        }

        static Expression<Func<ScheduledTaskEntity, IQueryable<ScheduledTaskLogEntity>>> ExecutionsSTExpression =
            ct => Database.Query<ScheduledTaskLogEntity>().Where(a => a.ScheduledTask == ct);
        [ExpressionField("ExecutionsSTExpression")]
        public static IQueryable<ScheduledTaskLogEntity> Executions(this ScheduledTaskEntity e)
        {
            return ExecutionsSTExpression.Evaluate(e);
        }

        public static Polymorphic<Func<ITaskEntity, Lite<IEntity>>> ExecuteTask = new Polymorphic<Func<ITaskEntity, Lite<IEntity>>>();

        public class ScheduledTaskPair
        {
            public ScheduledTaskEntity ScheduledTask;
            public DateTime NextDate;
        }

        static ResetLazy<List<ScheduledTaskEntity>> ScheduledTasksLazy;

        static PriorityQueue<ScheduledTaskPair> priorityQueue = new PriorityQueue<ScheduledTaskPair>((a, b) => a.NextDate.CompareTo(b.NextDate));

        static Timer timer = new Timer(new TimerCallback(TimerCallback), // main timer
                                null,
                                Timeout.Infinite,
                                Timeout.Infinite);


        public static void Start(SchemaBuilder sb, DynamicQueryManager dqm)
        {
            if (sb.NotDefined(MethodInfo.GetCurrentMethod()))
            {
                AuthLogic.AssertStarted(sb);
                OperationLogic.AssertStarted(sb);

                Implementations imp = sb.Settings.GetImplementations((ScheduledTaskEntity st) => st.Task);
                Implementations imp2 = sb.Settings.GetImplementations((ScheduledTaskLogEntity st) => st.Task);

                if (!imp2.Equals(imp2))
                    throw new InvalidOperationException("Implementations of ScheduledTaskEntity.Task should be the same as in ScheduledTaskLogEntity.Task");

                PermissionAuthLogic.RegisterPermissions(SchedulerPermission.ViewSchedulerPanel);

                ExecuteTask.Register((ITaskEntity t) => { throw new NotImplementedException("SchedulerLogic.ExecuteTask not registered for {0}".FormatWith(t.GetType().Name)); });

                SimpleTaskLogic.Start(sb, dqm);
                sb.Include<ScheduledTaskEntity>();
                sb.Include<ScheduledTaskLogEntity>();

                dqm.RegisterQuery(typeof(HolidayCalendarEntity), () =>
                     from st in Database.Query<HolidayCalendarEntity>()
                     select new
                     {
                         Entity = st,
                         st.Id,
                         st.Name,
                         Holidays = st.Holidays.Count,
                     });


                dqm.RegisterQuery(typeof(ScheduledTaskEntity), () =>
                    from st in Database.Query<ScheduledTaskEntity>()
                    select new
                    {
                        Entity = st,
                        st.Id,
                        st.Task,
                        st.Rule,
                        st.Suspended,
                        st.MachineName,
                        st.ApplicationName
                    });

                dqm.RegisterQuery(typeof(ScheduledTaskLogEntity), () =>
                    from cte in Database.Query<ScheduledTaskLogEntity>()
                    select new
                    {
                        Entity = cte,
                        cte.Id,
                        cte.Task,
                        cte.ScheduledTask,
                        cte.StartTime,
                        cte.EndTime,
                        cte.ProductEntity,
                        cte.MachineName,
                        cte.User,
                        cte.Exception,

                    });

                dqm.RegisterExpression((ITaskEntity ct) => ct.Executions(), () => TaskMessage.Executions.NiceToString());
                dqm.RegisterExpression((ITaskEntity ct) => ct.LastExecution(), () => TaskMessage.LastExecution.NiceToString());
                dqm.RegisterExpression((ScheduledTaskEntity ct) => ct.Executions(), () => TaskMessage.Executions.NiceToString());

                new Graph<HolidayCalendarEntity>.Execute(HolidayCalendarOperation.Save)
                {
                    AllowsNew = true,
                    Lite = false,
                    Execute = (c, _) => { },
                }.Register();

                new Graph<HolidayCalendarEntity>.Delete(HolidayCalendarOperation.Delete)
                {
                    Delete = (c, _) => { c.Delete(); },
                }.Register();

                new Graph<ScheduledTaskEntity>.Execute(ScheduledTaskOperation.Save)
                {
                    AllowsNew = true,
                    Lite = false,
                    Execute = (st, _) => { },
                }.Register();

                new Graph<ScheduledTaskEntity>.Delete(ScheduledTaskOperation.Delete)
                {
                    Delete = (st, _) =>
                    {
                        st.Executions().UnsafeUpdate().Set(l => l.ScheduledTask, l => null).Execute();
                        var rule = st.Rule; st.Delete(); rule.Delete();
                    },
                }.Register();


                new Graph<IEntity>.ConstructFrom<ITaskEntity>(TaskOperation.ExecuteSync)
                {
                    Construct = (task, _) => ExecuteSync(task, null, UserHolder.Current).Try(l => l.Retrieve())
                }.Register();

                new Graph<ITaskEntity>.Execute(TaskOperation.ExecuteAsync)
                {
                    Execute = (task, _) => ExecuteAsync(task, null, UserHolder.Current)
                }.Register();

                ScheduledTasksLazy = sb.GlobalLazy(() =>
                    Database.Query<ScheduledTaskEntity>().Where(a => !a.Suspended &&
                        (a.MachineName == ScheduledTaskEntity.None || a.MachineName == Environment.MachineName && a.ApplicationName == Schema.Current.ApplicationName)).ToList(),
                    new InvalidateWith(typeof(ScheduledTaskEntity)));

                ScheduledTasksLazy.OnReset += ScheduledTasksLazy_OnReset;

                ExceptionLogic.DeleteLogs += ExceptionLogic_DeleteLogs;
            }
        }

        public static void ExceptionLogic_DeleteLogs(DeleteLogParametersEntity parameters)
        {
            Database.Query<ScheduledTaskLogEntity>().Where(a => a.StartTime < parameters.DateLimit).UnsafeDeleteChunks(parameters.ChunkSize, parameters.MaxChunks);
        }

        static void ScheduledTasksLazy_OnReset(object sender, EventArgs e)
        {
            if (running)
                Task.Factory.StartNew(() => { Thread.Sleep(1000); ReloadPlan(); });
        }


        static bool running = false;
        public static bool Running
        {
            get { return running; }
        }

        public static void StartScheduledTasks()
{'fraction_non_alphanumeric': 0.09414127096621781, 'fraction_numerical': 0.0009449562957713206, 'mean_word_length': 1.8487550471063257, 'pattern_counts': {'":': 0, '<': 79, '<?xml version=': 0, '>': 141, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3866075', 'n_tokens_mistral': 4330, 'n_tokens_neox': 4018, 'n_words': 716}