[[PageOutline(2-5,Contents,pullout)]] = Trac task scheduler, recurring tasks == Description This plugin adds a scheduler inside the Trac process that can handle any task written in the Python language. It allows you to have any function of a Trac related process to be added as a job. Key features: * Tasks are implemented as Python plugins * Comes bundled with out-of-the-box tasks * Scheduler is implemented as a plugin * Bundled out-of-the-box scheduler; '''new''': cron syntax is supported * Listener mechanism allows the user to be notified of task execution * Bundled out-of-the-box listener; '''new''': admin panel for listener * Task execution history can be viewed through an rss feed The plugin provides an administration panel to help with scheduling: [[Image(tcp_admin_panel.png, 80%, border=2)]] To add a task to the scheduler simply create in a module (.py) a class that implements the ICronTask and put it in the `plugins` directory. Then you can either modify your `trac.ini` file or use the Trac cron admin panel. === Writing a task To implement a task you have to write a Python class that inherits ICronTask: {{{#!python class ICronTask(Interface): """ Interface for component task """ def wake_up(self, *args): """ Call by the scheduler when the task need to be executed """ raise NotImplementedError def getId(self): """ Return the key to use in trac.ini to configure this task """ raise NotImplementedError def getDescription(self): """ Return the description of this task to be used in the admin panel. """ raise NotImplementedError }}} Let's take a look at the heartbeat task included with TracCronPlugin: {{{#!python class HeartBeatTask(Component,ICronTask): """ This is a simple task for testing purpose. It only write a trace in log a debug level """ implements(ICronTask) def wake_up(self, *args): if len(args) > 0: for arg in args: self.env.log.debug("Heart beat: " + arg) else: self.env.log.debug("Heart beat: boom boom !!!") def getId(self): return "heart_beat" def getDescription(self): return self.__doc__ }}} You need to implement the interface and to put the definition of the task inside the '''wake_up''' method. === Installing a task Since tasks are components, you just have to put the class definition of your task in a Python module in the `plugins` directory. You can either create a .py file and put it in the `plugins` directory or you can package the .py file into an egg and leave it in the `plugins` directory. TracCronPlugin will show the task in the administration panel. Other examples of how to implement recurring tasks are given below. == Bugs/Feature Requests Existing bugs and feature requests for TracCronPlugin are [report:9?COMPONENT=TracCronPlugin here]. If you have any issues, create a [/newticket?component=TracCronPlugin new ticket]. [[TicketQuery(component=TracCronPlugin,group=type,format=progress)]] == Download Download the zipped source from [export:traccronplugin here]. The current stable release is '''0.3.1'''. The plugin is also available on [pypi:TracCronPlugin PyPI]. == Source You can check out TracCronPlugin from [/svn/traccronplugin here] using Subversion, or [source:traccronplugin browse the source] with Trac. == Installation You can use `pip install` to download and install the latest package into your Python environment: {{{#!sh $ pip install TracCronPlugin }}} == Configuration The plugin can be entirely configured from either within the `trac.ini` file or from the administration panel. The section name of TracCronPlugin is `traccron`, here is a full sample: {{{#!ini [traccron] ticker_enabled = True ticker_interval = 1 heart_beat.daily = 21h19, 21h20 heart_beat.daily.enabled = True hear_beat_daily.arg = Good Morging heart_beat.enabled = True heart_beat.hourly = 17, 18 heart_beat.hourly.enabled = False heart_beat.monthly = 15@21h15, 15@21h16 heart_beat.monthly.enabled = False heart_beat.weekly = 4@21h28, 4@21h29 heart_beat.weekly.enabled = False }}} === Global settings This controls the object called ticker, which is the thread that launches tasks. If False, no ticket (no thread) is created, so your Trac behaves like there is no cron installed. This is the global setting you can act on to enable or disable all tasks. Default value is '''True''': {{{#!ini ticker_enabled = True }}} This key controls the interval between each wake up of the ticker. The ticker thread periodically wakes up to see if there is a task to execute. Then the ticker thread goes to sleep for the amount of minutes specified by this key. You should not have to modify this value, except if you have system load issues. Default value is '''1''': {{{#!ini ticker_interval = 1 }}} === Task settings For each task loaded by the Trac Component manager, Trac Cron Plugin has those parameters. Let's look at a heart beat task. ==== Enabling and disabling a task This is the second way to enable or disable a task. Since ''ticker_enabled'' is global and so all tasks will be affected, this key only affects one task. If False, whatever schedule the task has, none will be triggered. So this is a way to disable a task, while keeping the schedule in place for the time you will enable the task. Default is '''True''': {{{#!ini heart_beat.enabled = True }}} ==== Task scheduling This controls the daily scheduler. As the name suggests, it triggers the task every day. Provide the time you want the task to execute. You can give a comma separated list to trigger the task at multiple times everyday. Default is no value: {{{#!ini heart_beat.daily = 21h19, 21h20 }}} The goal of this scheduler is to trigger the task every hour. Provide the minute when you want the task to be executed. Accepts comma separated values. Default is no value: {{{#!ini heart_beat.hourly = 17, 18 }}} This scheduler triggers a task that needs to be executed once a month. Provide the day in month and the hour when the task will be launched. The day is the index of the day starting at 1. Accepts comma separated values. Default is no value: {{{#!ini heart_beat.monthly = 15@21h15, 15@21h16 }}} This scheduler triggers a task that needs to be executed once a week. Provide the day in week and the hour when the task will be launched. The day is the index of the day starting at 0 (Monday is 0). Accepts comma separated values. Default is no value: {{{#!ini heart_beat.weekly = 4@21h28, 4@21h29 }}} ==== Enabling and disabling a schedule Each schedule can individually be enabled or disabled. This the configuration for the daily scheduler: {{{#!ini heart_beat.daily.enabled = True }}} This enables or disables the trigger. If False, the scheduler will not trigger the task. Default is '''True'''. ==== Pass argument to a task You can pass arguments to the task on a per schedule basis. Here an example for a daily schedule: {{{#!ini hear_beat_daily.arg = Good Morning }}} When the daily schedule triggers the task, the value of the key is passed to the '''wake_up''' call. Parameters can be comma separated values. Default is '''empty'''. == Bundled Task Besides the HeartBeat task provided for testing purposes, TracCronPlugin comes with the following useful tasks. === sleeping_ticket This task reminds the reporter about orphaned tickets and the assigned user about sleeping tickets. * An orphaned ticket is a ticket with status New for more than a given amount of days. An email notification is sent to the reporter in such a case. * A sleeping ticket is a ticket assigned to a user, but the user either did not accept it or did not touch the ticket (added a comment for example) for more than a given amount of days. The assigned user is notified in such a case. The delay is an optional parameter associated with each schedule. Default value is '''3 days'''. === unreachable milestone '''Note''': Since 0.2dev_r9388 This task scans still opened tickets in near milestone. Such a situation means that those tickets will probably not be part of the milestone. The task sends an email to the user defined with ''unreachable_milestone.recipient'' (default is '''empty''') for each milestone with the list of still opened tickets. You may want to set the value to the release manager user. Reporter and owner are notified too, but only for their tickets. The task looks for the nearest milestone until '''3 days ahead'''. You can change the value with parameter either by setting ''unreachable_milestone..arg'' or in the admin panel. This is an example of the mail for release manager: {{{ Hello, The milestone milestone1 is near to be closed. Its due date is 11-30-2010. Unfortunately we have detected some open tickets. Please consider to postpone them or ensure they will meet the milestone due date. These ticket are: testing ticket http://localhost:8000/dummy/ticket/1 testing ticket http://localhost:8000/dummy/ticket/3 Best regards. -- My Project My example project }}} === Auto postpone task '''Note''': since 0.2dev_r9390. Trac allows the administrator to postpone still opened tickets in a given milestone when he closes this milestone. But this is not mandatory. The auto postpone task will help to not forget opened tickets in a closed milestone. The task looks for such tickets and postpones them in the more recent still opened milestone. Milestone must have a due date. === Ticket deadline task '''Note''': since 0.3. This task notifies to the ticket's reporter and owner when its ticket is near the deadline as a custom field. You can add a date field for ticket using the DateFieldPlugin. Besides scheduler settings, there are the following options to configure when the DateFieldPlugin is used: - days_before: notify days before the deadline - date_field: ticket custom field's name - date_format: this format string is handled by datetime module [[Image(ticket-with-duedate.png, border=2)]] Here is a sample configuration for the `trac.ini` file: {{{#!ini [traccron] ticker_enabled = True ticker_interval = 1 ticket_deadline.cron = * 0 10 * * ? * ticket_deadline.cron.enabled = True ticket_deadline.enabled = True days_before=3 date_field=due_date date_format=%Y-%m-%d [ticket-custom] due_date = text due_date.date = true due_date.label = Due Date due_date.value = YYYY-MM-DD due_date.date_empty = true [datefield] format = ymd separator = - first_day = 1 }}} == Bundled Scheduler === Hourly scheduler See task scheduling section. === Daily scheduler See task scheduling section. === Weekly scheduler See task scheduling section. === Monthly scheduler See task scheduling section. === Cron Scheduler Since 0.2dev_r9375 there is a cron scheduler. You can use cron syntax to define the schedule. Currently you can use: * single value * range value both with - or / special character * special value * Example with ''heart_beat'' task: {{{#!ini heart_beat.cron = * 0/2 * * * ? * }}} '''Warning''': since TracCronPlugin ticker interval is at least one minute, this means the seconds cannot be specified and so the first item of the cron expression is useless. The cron like expression is here. Set either day-of-month or day-of-week and the other one must be '?': {{{ ex: * * * ? * ? * ┬ ┬ ┬ ┬ ┬ ┬ ┬ │ │ │ │ │ │ └──── year (omissible) │ │ │ │ │ └─────── day of week (1 - 7, 1 is Monday) │ │ │ │ └────────── month (1 - 12) │ │ │ └───────────── day of month (1 - 31) │ │ └──────────────── hour (0 - 23) │ └─────────────────── min (0 - 59) └────────────────────── None (reserved?) }}} Please refer to cron documentation for more details on the standard [wikipedia:CRON_expression cron syntax]. == Bundled Listener === Email notification of task event This listener notifies by email about task execution. You can choose the number of event sent by email by setting the value of ''email_task_event.limit''. When the listener has received at least the number of task execution, it will send the email. Default is '''1'''. The value of ''email_task_event.recipient'' '''must''' be filled, otherwise no email will be sent. Here is the configuration for this listener: {{{#!ini email_task_event.enabled = True email_task_event.limit = 1 email_task_event.recipient = admin }}} Here an sample of the email : {{{ The above task has been run by Trac Cron Plugin task[heart_beat] started at 0 h 47 ended at 0 h 47 success task[heart_beat] started at 0 h 48 ended at 0 h 48 success task[heart_beat] started at 0 h 49 ended at 0 h 49 success }}} Since 0.2dev_r9385 you can use ''email_task_event.only_error = True'' to send email only on error. == Recent Changes [[ChangeLog(traccronplugin, 3)]] == Author/Contributors '''Author:''' [wiki:tbressure] [[BR]] '''Maintainer:''' [[Maintainer]][[BR]] '''Contributors:'''