Orchard CMS中的定时任务

3

我需要使用Orchard CMS创建一个定时任务。

我有一个服务方法(假设它从外部数据源加载一些数据),我需要每天早上8:00执行它。

我发现我需要使用IScheduledTaskHandler和IScheduledTaskManager...有没有人知道如何解决这个问题?欢迎提供一些示例代码。

2个回答

12

在你的IScheduledTaskHandler中,你需要实现Process方法来提供你的任务实现(我建议你把你的实现放在另一个服务类中),并且你需要在任务管理器中注册你的任务。在处理程序构造函数中注册第一个任务,然后在处理实现中,确保一旦一个任务被执行,下一个任务就会被调度。

这是一个示例:

    public class MyTaskHandler : IScheduledTaskHandler
    {
      private const string TaskType = "MyTaskUniqueID";
      private readonly IScheduledTaskManager _taskManager;

      public ILogger Logger { get; set; }

      public MyTaskHandler(IScheduledTaskManager taskManager)
      {
        _taskManager = taskManager;
        Logger = NullLogger.Instance;
        try
        {
          DateTime firstDate = //Set your first task date (utc).
          ScheduleNextTask(firstDate);
        }
        catch(Exception e)
        {
           this.Logger.Error(e,e.Message);
        }
      }

      public void Process(ScheduledTaskContext context)
      {
         if (context.Task.TaskType == TaskType)
         {
           try
           {
                   //Do work (calling an IService for instance)
           }
           catch (Exception e)
           {
             this.Logger.Error(e, e.Message);
           }
           finally
           {
             DateTime nextTaskDate = //Your next date (utc).
             this.ScheduleNextTask(nextTaskDate);
           }         
         }
      }
      private void ScheduleNextTask(DateTime date)
      {
         if (date > DateTime.UtcNow )
         {
            var tasks = this._taskManager.GetTasks(TaskType);
            if (tasks == null || tasks.Count() == 0)
              this._taskManager.CreateTask(TaskType, date, null);
          }
      }


    }

这个方法可以工作,但会添加多个任务。有其他启动进程的方式吗? - Carl
1
这正是我所需要的。谢谢。 - bingles
IScheduledTaskHandler 是 IEventHandler 的一种,这意味着它在每个工作范围内实例化一次,其中任何事件总线上的内容都会被处理(例如在应用程序启动和关闭期间以及在每个 Web 请求期间的某个时刻)。任务被添加多次的原因是因为该类在构造函数中调用 ScheduleNextTask。 - Katsuyuki Omuro

2

为避免添加多个任务,请使用IOrchardShellEvents的实现来进行第一次调度,而不是在任务构造函数中进行。

以下是您可以实现的抽象DailyTaskHandler类:

用法

public class MyTaskHandler : DailyTaskHandler {
    private readonly IMyService _myService;

    public MyTaskHandler(IMyService myService,
        IDailyTasksScheduler dailyTasksScheduler) : base(dailyTasksScheduler) {
        _myService = myService;
    }

    public override int Hour => base.Hour; // you can override default hour

    public override void Process() => _myService.DoStuff();
}

抽象的日常任务处理器和调度器

public abstract class DailyTaskHandler : IDailyTaskHandler, IScheduledTaskHandler {
    private readonly IDailyTasksScheduler _dailyTasksScheduler;

    protected DailyTaskHandler(IDailyTasksScheduler dailyTasksScheduler) {
        _dailyTasksScheduler = dailyTasksScheduler;
        Logger = NullLogger.Instance;
        TaskType = GetType().FullName;
    }

    public ILogger Logger { get; set; }

    public virtual int Hour { get; } = 1; // default scheduled hour of the day

    public string TaskType { get; }

    public void Process(ScheduledTaskContext context) {
        if (context.Task.TaskType == TaskType) {
            Logger.Information($"Process task: {TaskType}");
            try {
                Process();
            }
            catch (Exception e) {
                Logger.Error(e, e.Message);
            }
            finally {
                _dailyTasksScheduler.Schedule(this);
            }
        }
    }

    public abstract void Process();
}

public class DailyTasksStarter : IOrchardShellEvents {
    private readonly IEnumerable<IDailyTaskHandler> _dailyTaskHandlers;
    private readonly IDailyTasksScheduler _dailyTasksScheduler;

    public DailyTasksStarter(
        IEnumerable<IDailyTaskHandler> dailyTaskHandlers,
        IDailyTasksScheduler dailyTasksScheduler) {
        _dailyTaskHandlers = dailyTaskHandlers;
        _dailyTasksScheduler = dailyTasksScheduler;
    }

    public void Activated() => _dailyTasksScheduler.Schedule(_dailyTaskHandlers);

    public void Terminating() { }
}

public class DailyTasksScheduler : IDailyTasksScheduler {
    private readonly IScheduledTaskManager _scheduledTaskManager;

    public DailyTasksScheduler(IScheduledTaskManager scheduledTaskManager) {
        _scheduledTaskManager = scheduledTaskManager;
    }

    public void Schedule(IDailyTaskHandler dailyTaskHandler) => Schedule(new IDailyTaskHandler[] { dailyTaskHandler });

    public void Schedule(IEnumerable<IDailyTaskHandler> dailyTaskHandlers) {
        DateTime nextDay = DateTime.UtcNow.AddDays(1);
        foreach (var dailyTaskHandler in dailyTaskHandlers) {
            DateTime nextTaskDate = new DateTime(nextDay.Year, nextDay.Month, nextDay.Day, dailyTaskHandler.Hour, 0, 0, DateTimeKind.Utc);
            if (nextTaskDate > DateTime.UtcNow && _scheduledTaskManager.GetTasks(dailyTaskHandler.TaskType)?.Any() != true) {
                _scheduledTaskManager.CreateTask(dailyTaskHandler.TaskType, nextTaskDate, null);
            }
        }
    }
}

public interface IDailyTaskHandler : IDependency {
    int Hour { get; }
    string TaskType { get; }
}

public interface IDailyTasksScheduler : IDependency {
    void Schedule(IDailyTaskHandler dailyTaskHandler);
    void Schedule(IEnumerable<IDailyTaskHandler> dailyTaskHandlers);
}

您可以通过在任务处理程序类上实现调度方法和IOrchardShellEvents接口来避免使用任务调度器类。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接