ERP 2.50:Developers Guide/Concepts/Process Scheduling
Contents |
Overview
Openbravo Process Scheduling is a framework to provide developers and users with finer control over process scheduling and monitoring within Openbravo ERP. Openbravo ERP release 2.50 leverages the power and flexibility of the Quartz Job Scheduling Framework.
Glossary
- Process
- Refers to a unit of work that can be scheduled to execute in the application's Scheduler.
- ProcessBundle
- Is the detail of a Process, which includes identifying, contextual and security information, parameters and a log of the process' execution.
- Scheduler
- Manages the execution of Processes (Jobs).
- Job
- Is the Quartz representation of what Openbravo ERP calls a Process - a unit of work that can be scheduled to execute.
- Trigger
- Is a definition of the instance(s) of time when a Process should be executed. A Quartz Job is scheduled in the Scheduler with a specified Trigger.
Why Quartz?
Quartz is a robust, scalable and extensible open source process scheduling framework that can be integrated into virtually any Java EE or Java SE application. There are a number of reasons why Quartz is especially suitable to Openbravo ERP as a process scheduling framework;
- Is simple: Quartz provides a robust and well designed API that is easy to extend to fit an application's own unique needs. Implementing the Job interface is all that is required for a unit of work to be scheduled and executed within the Quartz framework.
- Is configurable: Quartz enables developers to customize the configuration of the scheduling environment by modifying a properties file which is loaded on application server/servlet container startup.
- Listeners: Quartz provides the ability to define listeners to do basically whatever you want in response to process behavior and events. Examples of such events are process failure or success, when a process is about to fire or has misfired (not fired when it was supposed to) etc.
- Plugins: Quartz also provides the ability to define plugins that perform custom functionality when the scheduler starts up and shuts down.
On top of its extensibility, Quartz provides a very flexible range of scheduling options, including nearly any combination of the following:
- At a certain time of the day.
- On certain days of the week.
- On certain days of the month.
- On certain days of the year.
- For a number a repetitions.
- Repeated for until a certain time/date.
- Repeated with a delay interval and indefinitely.
- To a specified Quartz cron expression.
- Avoiding certain days specified in a calendar.
Quartz Configuration
The Quartz jar is included in the lib/runtime folder and org.openbravo.base.OBSchedulerInitializerListener, an implementation of javax.servlet.ServletContextListener, is configured as a listener in the AD_MODEL_OBJECT table. When Tomcat is started, OBSchedulerInitializer listener is loaded and configures the scheduler environment with the parameters defined in the web.xml and in the quartz.properties file (see below). OBSchedulerInitializerListener is basically a replica of the Quartz provided org.quartz.ee.servlet.QuartzInitializerListener listener, but also stores a reference to the Openbravo Connection Pool and Config Parameters in the scheduler's context. This ensures that these object's are available to the Openbravo Scheduler and Monitor when processes are scheduled and process events occur.
<!-- Quartz context params --> <context-param> <param-name>config-file</param-name> <param-value>quartz.properties</param-value> </context-param> <context-param> <param-name>shutdown-on-unload</param-name> <param-value>true</param-value> </context-param> <context-param> <param-name>start-scheduler-on-load</param-name> <param-value>true</param-value> </context-param> <context-param> <param-name>start-delay-seconds</param-name> <param-value>30</param-value> </context-param>
Although not necessary as default properties are internally configured in Quartz, Openbravo ERP provides a default quart.properties file to make adding or modifying properties a breeze:
## Quartz properties org.quartz.scheduler.instanceName = DefaultQuartzScheduler org.quartz.scheduler.rmi.export = false org.quartz.scheduler.rmi.proxy = false org.quartz.scheduler.wrapJobExecutionInUserTransaction = false org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.threadCount = 10 org.quartz.threadPool.threadPriority = 5 org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true org.quartz.jobStore.misfireThreshold = 60000 org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
For a full list of configuration options see this Quartz Configuration document.
Process Scheduling
You can view the Process Request window by navigating in the Menu to General Setup -> Process Scheduling -> Process Request. Here you can see the typical Openbravo ERP window options, but in particular notice the Process and Timing options. These two fields allow you to select the background process to run and how it will be run, or more specifically for development purposes, the Trigger that will be used/generated for Scheduler.
When requesting a process through the Process Request window, there are three options that a user can select from:
- Run Immediately - Executes the process a single time, immediately.
- Run Later - Allows the user to specify a start date and time at which the process will run.
- Schedule - Allows the user to select from a range of options which harness the full power of the Quartz framework.
Schedule Options
These options enable users of the system to fine tune exactly when a background process will start, repeat and stop, and are translated into Quartz Triggers and fed into the underlying scheduling framework when the process is scheduled.
TriggerProvider is a private inner class in OBScheduler (discussed below), which takes the options entered by the user in the Process Request window and transforms them into Quartz Triggers which can be fed into the Quartz Scheduler along with the Processes (Jobs) to be executed.
Scheduling by seconds, minutes and hours
When scheduling by seconds, minutes or hours, two options are given: the interval between the seconds/minutes/hours, and the number of repetitions that will be performed before the process stops repeating (if left blank it will continue indefinitely, except when a finish date is specified). TriggerProvider uses the Quartz TriggerUtils, a utility class that simplifies creating simple triggers, to transform the selected values into a scheduleable Quartz Trigger:
int i = Integer.parseInt(interval); int r = Integer.parseInt(repetitions); ... if (type.equals(FREQUENCY_SECONDLY)) { return TriggerUtils.makeSecondlyTrigger(i, r); } else if (type.equals(FREQUENCY_MINUTELY)) { return TriggerUtils.makeMinutelyTrigger(i, r); } else if (type.equals(FREQUENCY_HOURLY)) { return TriggerUtils.makeHourlyTrigger(i, r); }
Scheduling daily
Daily provides an identical selection as explained above in seconds, minutes and hours, but also allows users to schedule the process on Weekdays or Weekends:
Daily scheduling options are transformed into a Quartz CronTrigger for use by the scheduler. CronTriggers follow the same formatting rules as a typical cron expression in a Linux system. More about Quartz CronTriggers can be found in their tutorial and in the Quartz documentation.
} else if (data.dailyOption.equals(WEEKDAYS)) { final String cronExpression = second + " " + minute + " " + hour + " ? * MON-FRI"; trigger = new CronTrigger(name, OB_GROUP, cronExpression); } else if (data.dailyOption.equals(WEEKENDS)) { final String cronExpression = second + " " + minute + " " + hour + " ? * SAT,SUN"; trigger = new CronTrigger(name, OB_GROUP, cronExpression);
Scheduling weekly
Scheduling weekly allows users to select individual days of the week to execute the process:
And similar to the Triggers generated when users schedule a process on weekdays or weekends, a CronTrigger is generated by TriggerProvider that represents the days selected:
} else if (data.frequency.equals(FREQUENCY_WEEKLY)) { final StringBuilder sb = new StringBuilder(); if (data.daySun.equals("Y")) sb.append("SUN"); if (data.dayMon.equals("Y")) sb.append(sb.length() == 0 ? "MON" : ",MON"); ... if (sb.length() != 0) { sb.insert(0, second + " " + minute + " " + hour + " ? * "); trigger = new CronTrigger(name, OB_GROUP, sb.toString());
Scheduling monthly
Monthly offers a few more variances than in the preceding options:
- 01 - First, 02 - Second, 03 - Third and 04 - Fourth allow users to specify a particular day (i.e. Monday, Wednesday) of the month.
- Last day of the Month - allow users to specify the last day of each month.
- Specific day - allows users to schedule process on a specific day of the month (i.e. 15th of the month).
All of the monthly options are transformed by TriggerProvider into CronTriggers in much the same way the Weekly option is.
Scheduling by cron expression
Finally there is an option to directly enter a Quartz cron expression which is directly transformed into a CronTrigger. If the expression is malformed, an error will be thrown. For details on CronTrigger format, see the JavaDoc.
Quartz Scheduler Integration
At the heart of the Quartz scheduling framework is the org.quartz.Scheduler. The scheduler is responsible for Job and Trigger management, scheduling and unscheduled tasks and retrieving and updating scheduler state and information.
Openbravo Process Scheduling creates a simple interface to the Quartz Scheduler via the org.openbravo.scheduling.OBScheduler, a singleton instance that is initialized at startup and exposes a number of methods to schedule Openbravo Processes. The underlying Quartz Scheduler is available by calling the getScheduler() method on the OBScheduler instance. This enables developers full access to the power of the underlying Quartz framework, especially for registering custom Listeners and retrieving Scheduler information.
Job/Process Integration
The interface org.openbravo.scheduling.Process needs to be implemented in order to be scheduled directly with the OBScheduler and monitored by the Process Monitor. A base implementation of Process is provided in the org.openbravo.service.db.DalBaseProcess, which should be extended in preference of directly implementing Process, as the DalBaseProcess class provides built in security.
The org.openbravo.scheduling.ProcessBundle is the class which is passed to Openbravo Processes as the only parameter to the execute() method. Any parameters that a process needs should be stored in the ProcessBundle's parameter Map. ProcessBundle also provides access to process specific contextual information Openbravo application information. By using the ProcessLogger, which is also wrapped up in the ProcessBundle, developers are able to log messages which will be displayed in the Process' log on the Process Monitor window.
The org.openbravo.scheuling.DefaultJob is an implementation of the Quartz Job interface and takes care of the integration between Quartz and Openbravo ERP. The DefaultJob is what is scheduled with the Quartz Scheduler; an Openbravo Process (and its ProcessBundle) is stored and retrieved from the DefaultJob's execution context when it is scheduled, executed and whenever the Process Monitor requires it. For example:
public void execute(JobExecutionContext jec) throws JobExecutionException { final ProcessBundle bundle = (ProcessBundle) jec.getMergedJobDataMap().get(ProcessBundle.KEY); try { final Process process = bundle.getProcessClass().newInstance(); ... process.execute(bundle);
Demonstrates retrieving the Openbravo Process and ProcessBundle from the DefaultJob when it is executed by the Quartz Scheduler.
Process Monitoring
Monitoring process execution in the application is done via the General Setup -> Process Scheduling -> Process Monitor window:
Monitoring is achieved through the use of Quartz Listeners. You register listeners with the Scheduler to perform an action when a specific event occurs within the scheduling environment, such as when a Job is executed or fails. The org.openbravo.scheduling.ProcessMonitor class implements Quartz JobListener, TriggerListener and SchedulerListener and responds to the following events:
- jobScheduled: Updates the Process Request status to Scheduled.
- triggerFired: Updates the Process Request start time and status.
- jobToBeExecuted: Updates the Process Execution status to Processing.
- jobWasExecuted: Updates the Process Execution timings and duration.
- triggerFinalized: Updates the Process Request finish time.
- jobUnscheduled: Updates the Process Request status to Unscheduled.
- triggerMisfired: Updates the Process Request status to Error.
For a full listing of listener events see JobListener, TriggerListener and SchedulerListener.
Languages: |
ERP 2.50:Developers Guide/Concepts/Data Access Layer | ERP 2.50:Developers Guide/Concepts/Authentication