Creating timers using the EJB timer service for enterprise beans

You can use enterprise beans to take advantage of the EJB timer service to schedule time-based events.

About this task

In support of the EJB 3.1 specification, you can create non-persistent EJB timers. This product also supports the expanded TimerService API for programmatic timer creation. In addition, you can configure the EJB container to automatically create a timer when the application starts.

WebSphere® Application Server implements the Enterprise JavaBeans(EJB) timer service. Based on your business needs, you can use persistent timers or non-persistent timers. Persistent timers are helpful if you are creating a timer for a time-based event that requires assurance of timer existence beyond the life cycle of the server. Previously started persistent timers automatically start when your server starts and persist through server shutdowns and restarts. For example, you can use persistent timers to start a system application or send a status notification on the expiration of a timer. Non-persistent timers are helpful in non-critical situations where the timer actions are skipped or redone without negative business impacts, such as polling a temperature.

You can create timers programmatically. You can also create timers automatically by using the @Schedule annotation in the bean class, or by using the timer element in the ejb-jar.xml deployment descriptor. By automatically creating timers, you can schedule a timer without relying on your enterprise bean invocation to programmatically start an EJB timer service creation method.

Persistent timers

Persistent timers are implemented as a scheduler service task. By default, an internal or pre-configured scheduler instance is used to manage those tasks, and they persist in an Apache Derby database associated with the server process.

You can perform basic customizations to the internal scheduler instance. For information about customizing the scheduler instance, see the configuring a timer service information.

The creation and cancellation of Timers is transactional and persistent. If a Timer is created within a transaction and that transaction is later rolled back, the creation of the Timer is rolled back as well. Similar rules apply to the cancellation of a Timer. Previously started Timers are maintained across application server shutdowns and restarts.

Non-persistent timers

EJB 3.1 augments the EJB timer service to enable non-persistent EJB timers in addition to the persistent timers. Non-persistent timers have many of the same semantics and behavior as persistent timers, but without the overhead of a data store. Non-persistent timers have a different life cycle than persistent timers. Where persistent timers are maintained across application server shutdowns and restarts, non-persistent timers are active only while the application server is active. Unlike persistent timers, there are no commands to find or cancel non-persistent timers. Non-persistent timers are canceled when the application server is stopped or fails to remain in an active state.

As with persistent timers, the creation and cancellation of non-persistent timers is transactional. If a timer is created within a transaction and that transaction is later rolled back, the creation of the timer is rolled back as well. Similar rules apply to the cancellation of a timer.

You can configure non-persistent timers to share a thread pool with persistent timers, or to have a unique thread pool that is not shared with persistent timers.

Programmatically created timers

A programmatically created persistent timer is maintained across application server shutdowns and restarts, unless it is canceled. It is the responsibility of application code or system administrator to delete a programmatically created timer which is no longer wanted.

To programmatically create a timer that is associated with your enterprise bean, the bean calls the getTimerService() method on the applicable context instance to get a reference to the TimerService object. The bean also calls one of the TimerService methods, such as createTimer, to specify the timer for the bean. This Timer instance is now associated with your bean. The TimerService methods are described in the EJB 3.1 specification. You can now pass the Timer instance to other Java™ code as a local object. After the Java code obtains the Timer instance, the code can use any of the methods defined by the javax.ejb.Timer interface, such as the cancel() or getTimeRemaining() methods.

In a clustered environment, a programmatically created persistent timer can run in any cluster member, but a programmatically created non-persistent timer runs only in the same JVM in which it was created.

Automatically created timers
The EJB 3.1 specification augments the EJB timer service to enable the automatic creation of a timer when your application starts without relying on a bean invocation to programmatically start one of the timer service timer creation methods. Use the @Schedule annotation or the timeout-method deployment descriptor element to automatically create timers. Automatically created timers are created by the container as a result of application deployment.
Avoid trouble: The CancelEJBTimers command also cancels automatically created timers. When automatically created timers are canceled, the only way to recreate them is to uninstall the application and reinstall it again.
Timers in a clustered environment

In a clustered environment, a persistent timer runs only in one cluster member which might not necessarily be the same cluster member it was created in. A non-persistent timer runs in each cluster member that it was created in - automatic non-persistent timers run in each cluster member that contains the EJB.

Automatic persistent timers are removed from their persistent store when their containing module or application is uninstalled. Therefore, do not update applications that use automatic persistent timers with the Rollout Update feature. Doing so uninstalls and reinstalls the application while the cluster is still operational, which might cause failure in the following cases:

  • If a timer running in another cluster member activates after the database entry is removed and before the database entry is recreated, then the timer fails. In this case, a com.ibm.websphere.scheduler.TaskPending exception is written to the First Failure Data Capture (FFDC), along with the SCHD0057W message, indicating that the task information in the database has been changed or canceled.
  • If the timer activates on a cluster member that has not been updated after the timer data in the database has been updated, then the timer might fail or cause other failures if the new timer information is not compatible with the old application code still running in the cluster member.

When you use the proxy server in the product, do not define a scheduler at the cell level if that scheduler is configured as the one to use for the EJB timer service. Doing so prevents persistent timers from running. This can happen if the proxy server gets the scheduler lease. Since no applications run in the proxy server, there is no application code to handle the timer events that are sent by the scheduler.

Retries and missed timeouts

If you use EJB timers, you must understand the concepts of failure, retry, and missed timeouts.

  • A failure is a timeout execution that is attempted, but does not succeed.
  • A retry is an additional attempt to successfully execute a timeout that was previously attempted, but failed.
  • A missed execution is a timeout that must have been attempted, but was not, because the server was unavailable or busy retrying a previously failed timeout.
The retry behavior reflects:
  • Number of additional times that the server retries the failed timeout
  • Interval between these server retries
The missed timeout behavior reflects:
  • Whether the server eventually attempts missed timeouts, or not
  • If missed timeouts are eventually attempted, when those attempts occur
  • Interval between the missed timeout attempts
Table 1. Retry and missed timeout behavior. Retry and missed timeout behavior for both persistent and non-persistent timers.
Characteristic Default behavior Configurable
Number of retry attempts As many as it takes to succeed.

Persistent timers are temporarily deactivated if their scheduler failure threshold is reached in a server. For more information, see the topic about stopping tasks that are failing.

Yes, for non-persistent timers
Interval between retry attempts First retry attempt is immediate.

Subsequent retry attempts occur on the configured scheduler poll interval for persistent timers, and on the configured retry interval for non-persistent timers.

Yes
Missed timeout recovery All missed timeouts are recovered. No
When missed timeouts are recovered Both persistent and non-persistent timers recover missed timeouts when the blocking retry attempts stop. Additionally, persistent timers recover timeouts when an unavailable server restarts. No
Next timeout, after retry attempts are successful and missed timeouts are recovered At the next originally scheduled time. No

The configurable characteristics are configured on the scheduler instance for persistent timers and on the non-persistent timer configuration for non-persistent timers.

The following scenarios illustrate how the retry and missed timeout behavior influences the timeouts for both persistent and non-persistent timers.

Persistent timer scenario:

A persistent timer is created and configured to run for the first time at 10:00 am, and then run every hour after that. The scheduler supporting the timer is configured with a 30 second poll interval.

The timer runs at 10:00 am and fails because a database is unavailable. The timer is immediately retried, and retried again every 30 seconds when the scheduler is polled, and keeps failing, until 12:30 pm. At that moment, a retry attempt succeeds because the database is now back online, and therefore the server stops retrying the previously failed attempt.

Now, the server begins to work through the missed timeouts. First, it attempts the timeout that must have run at 11:00 am, which succeeds at 12:31 pm. When the scheduler is polled again 30 seconds later, it attempts the timeout that must have run at 12:00 pm, which succeeds at 12:32 pm. The server is now current, and the next timeout occurs at its originally scheduled time of 1:00 pm, as opposed to an hour after the last success, which would have been 1:32 pm. Going forward, the original schedule is maintained. The schedule is not updated based on the time of the last successful timeout.

Non-persistent timer scenario:

A non-persistent timer is created and configured to run for the first time at 10:00 am, and then run every hour after that. This non-persistent timer is configured to have a retry count of 5, and a retry interval of 30 minutes.

The timer runs at 10:00 am and fails because a database is not available. The timer is immediately retried, and fails again. Now, having executed the initial immediate retry, the server waits for the configured retry interval of 30 minutes between the next retry attempt. Retry attempts occur at 10:30 am and 11:00 am, and both fail. Finally, the fourth retry occurs at 11:30 am, and succeeds because the database is now back online.

Now, the server begins to work through the missed timeouts. The timeout that was originally scheduled for 11:00 am is immediately run, and succeeds at 11:31 am. The server is now current, and the next timeout occurs at its originally scheduled time of 12:00 pm (as opposed to an hour after the last success, which would be 12:32 pm).

Behavior of the getNextTimeout and getTimeRemaining methods

For both persistent and non-persistent timers, the Timer.getNextTimeout method returns a java.util.Date object that indicates the next time the timer is scheduled to execute. When you call the getNextTimeout method from a timeout callback method for an interval or calendar-based timer, the method returns the next scheduled time; for calendar-based timers with no future timeouts, the method throws the NoMoreTimeoutsException exception as required by the EJB 3.1 specification. When you call the getNextTimeout method from a timeout callback method for a single-action timer, the method returns the originally scheduled time. If a timeout callback method fails and retries are being attempted, the getNextTimeout method continues to return the originally scheduled time as if the failed execution had not occurred. In all cases, the Timer.getTimeRemaining method returns the difference in milliseconds between the getNextTimeout returned value and the current system time, which could result in a negative number, if the scheduled execution time was in the past.

Inheritance behavior of automatically created timers

Automatic timer methods in a hierarchy of bean classes cause multiple timers to be created. The number of timers associated with a timer method is not determined by the number of occurrences of the method in the source code. Instead, the number of timers associated with a timer method is determined by the number of beans with visibility to that method. For example:

@Stateless
public class Abean {

   @Schedule(hour=”1”)
   public void timerMethod1()


@Stateless
public class Bbean extends Abean {

   @Schedule(hour=”2”)
   public void timerMethod2()


@Stateless
public class Cbean extends Bbean {

   @Schedule(hour=”2”)
   public void timerMethod2()

In the previous bean class hierarchy, three automatic timers with callback method Abean.timerMethod1 are created, one for each bean instance with visibility to that method. One timer with callback method Bbean.timerMethod2 is created, and since that method is overridden by bean Cbean, only one timer with callback method Cbean.timerMethod2 is created.

In the previous example, when bean Abean is processed by the container, a single automatic timer is created, with callback method Abean.timerMethod1.

When the bean Bbean is processed by the container, an automatic timer is created with callback method Bbean.timerMethod2, and another automatic timer is created with callback method Abean.timerMethod1.

When the bean Cbean is processed by the container, an automatic timer is created with callback method CBean.timerMethod2. Another automatic timer is created with callback method Abean.timerMethod1. A timer for Bbean.timerMethod2 is not created when processing the bean Cbean. Bbean.timerMethod2 is not visible in the class hierarchy of Cbean because it is overridden by method Cbean.timerMethod2.

Consider another example like the previous one, if the @Stateless annotation were removed from classes Abean and Bbean, so that class Cbean is the only EJB. In that case, the only automatic timers created would be those visible to Cbean - one with callback method Abean.timerMethod1, one with callback method Cbean.timerMethod2.

Although beans can share identical code in an inherited bean callback method, the runtime behavior might be polymorphic. For example:

public class Employee {

   @Schedule(hour=”1”, dayOfMonth=”-1”, info = "payroll timer")
   public void getSalaryIncrease() {
      printChecks(salary * rate());
   }

   protected float rate() {
      return (float)1.01;
   }

}

public class Manager extends Employee {

   protected float rate() {
      return (float)1.15;
   }

}

public class Executive extends Manager {

   protected float rate() {
      return (float)1.30;
   }

}

In the previous example, each bean instance has an automatic timer with callback method getSalaryIncrease(). Although the same callback code is shared by each timer, note that the rate used in calculating the salary increase by each bean is different, due to polymorphism. That is, timer callback methods might be polymorphic in the same way that any Java methods might be.

Procedure

  • To create timers programmatically, define the timeout method using the @Timeout annotation, the timeout-method deployment descriptor element, or by implementing the javax.ejb.TimedObject interface.
    A bean can have at most one timeout method for timers that are created programmatically. The timeout method is identified by the @Timeout annotation in the source code, or by the timeout-method deployment descriptor element contained in the ejb-jar.xml file. The timeout method must accept no parameters or a single parameter of type javax.ejb.Timer.
    • Define the timeout method by using the @Timeout annotation to create timers programmatically. The following code is an example of using the @Timeout annotation within the MyBeanImpl class:
      class MyBeanImpl implements MyBean{
      @Timeout
      void myTimeOutMethod()
    • Define the timeout method by using the timeout method deployment descriptor element.

      You can write your enterprise bean to implement the javax.ejb.TimedObject interface, including the ejbTimeout() method. If the bean implements the TimedObject interface, there is no need to annotate a timeout method, and it is not valid unless that method is the ejbTimeout() method.

      The following code snippet illustrates using the timeout method deployment descriptor element within the ejb-jar.xml file:
      <timeout-method>
      <method-name>myTimeoutMethod</method-name>
      <method-params>
      <method-param>javax.ejb.Timer</method-param>
      </method-params>
      </timeout-method>
      In this case, the container starts the myTimeoutMethod method on a bean instance when a timer for that instance has expired. The instance is notified by the myTimeoutMethod method of the defined time-based event so the instance can run the associated business logic, based on the timer expiration notification.

      Now, you can pass the timer instance to other Java code as a local object. After the Java code obtains the timer instance, the code can use any of the methods defined by the javax.ejb.Timer interface, such as the cancel() or getTimeRemaining() methods.

      Note: ForWebSphereApplication Server Version 6, no assembly tool supports the EJB timedObject object. To set the ejbTimeout method transaction attribute, you must manually enter the attributes in the deployment descriptor.
    • Define the timeout method by using the javax.ejb.TimedObject interface.
      • Write your enterprise bean to implement the javax.ejb.TimedObject interface, including the ejbTimeout() method. The bean calls the EJBContext.getTimerService() method to get an instance of the TimerService object. The bean calls the TimerService method to create a timer. This Timer is now associated with that bean.
      • After you create the timer, you can pass the timer instance to other Java code as a local object.
      The ejbTimeout method can contain any code that is typically placed in a business method of the bean. Method-level attributes such as transaction or runAs can be associated with this method by the application assembler. An instance of the timer that causes the method to run is passed in as an argument to ejbTimeout method. The following code snippet illustrates using the javax.ejb.TimedObject interface:
      import javax.ejb.Timer;
      import javax.ejb.TimedObject;
      import javax.ejb.TimerService;
      
      public class MyBean implements EntityBean, TimedObject {
      
        // This method is called by the container when the timer expires.
        public void ejbTimeout(Timer theTimer) {
      
          //You can place code that is typically placed in an EJB method.
      
           String whyWasICalled = (String) theTimer.getInfo():
           System.out.println("I was called because of"+ whyWasICalled);
        } // end of method ejbTimeout
      A timer is created that starts the ejbTimeout method in 30 seconds. A simple string object is passed in at timer creation to identify the timer; for example:
      // Instance variable to hold the EJB context.
      private EntityContext theEJBContext;
      
      // This method is called by the EJB container upon bean creation.
      public void setEntityContext(EntityContext theContext) {
      
      // Save the entity context passed in upon bean creation.
        theEJBContext = theContext;
      
      }
      
      // This business method causes the ejbTimeout method to begin in 30 seconds.
      public void fireInThirtySeconds() throws EJBException  {
      
        TimerService theTimerService = theEJBContext.getTimerService();
        String aLabel = "30SecondTimeout";
        Timer theTimer = theTimerService.createTimer(30000, aLabel);
      
      } // end of method fireInThirtySeconds
      
      } // end of class MyBean
      Best practice: The EJB 3.x programming model provides additional strategic ways to define persistent and non-persistent timers within your business environments. Although defining persistent timers using the ejbTimeout method with the TimedObject interface is still supported, take advantage of the easy-to-implement EJB annotations to create persistent and non-persistent timers to meet your business needs.
  • Determine whether your timer must be single-action, interval, or calendar-based.
    • A single-action timer is scheduled to run once on a specific date or after a specified duration. To specify a single-action timer, use the TimerService.createSingleActionTime or TimerService.createTimer(Date, Serializable) APIs.

    • An interval timer is scheduled to begin on a specific date or after a specified duration and continues to run at a fixed rate until it is canceled. To specify an interval timer, use the TimerService.createIntervalTimer, TimerService.createTimer(long, long, Serializable), or TimerService.createTimer(Date, long, Serializable) APIs.

    • A calendar-based timer is scheduled to run at specific dates and times. To specify a calendar-based timer, either use an automatically created timer or use the TimerService.createCalendarTimer APIs, which accept a javax.ejb.ScheduleExpression argument.

      Supported configurations: When the EJB container stores a serialized calendar-based timer in the database, the serialized format is incompatible with the format used in WebSphere Application Server Version 7 and lower. If you use calendar-based timers, you must not configure the scheduler for the EJB container to use database tables that are shared with an older version of WebSphere Application Server.

      When using the TimerService.createCalendarTimer API, several attributes are specified to form an expression like the cron job scheduling daemon. The first set of attributes is used to control how date calculations are performed:

      Table 2. Attributes that control how dates are calculated.. Attributes that control how dates are calculated
      Attribute Description
      start Specifies a date value that is the inclusive starting point for calculating timeouts. The default value is null, which means the timer can start at any time.
      end Specifies a date value that is the inclusive ending point for calculating timeouts. The default value is null, which means the timer continues to run indefinitely.
      timezone Specifies a valid time zone according to the java.util.TimeZone API. The default value is null, which corresponds to the default time zone of the host server.

      The second set of attributes determines when the timer runs. All attributes have a set of allowable values in addition to a special wild-card value *, which represents all possible values for that attribute.

      Table 3. Attributes that determine when the timer runs.. Attributes that determine when the timer runs
      Attribute Description
      second Specifies an integer in the range 0 to 59; default 0.
      minute Specifies an integer in the range 0 to 59; default 0.
      hour Specifies an integer in the range 0 to 23; default 0.
      dayOfMonth Specifies an integer in the range 1 to 31; default *. Alternatively, the value can be:
      • The keyword Last, which corresponds to the last day of the month.
      • An integer in the range -1 to -7, which corresponds to a day before the last day of the month. For example, in a month with 31 days, the value -3 would correspond to the 28 day of the month.
      • The keyword 1st, 2nd, 3rd, 4th, 5th, or Last followed by a day of the week keyword Sun, Mon, Tue, Wed, Thu, Fri, or Sat. For example, you might use 3rd Sun and Last Wed. You must use the abbreviated English ordinals and keywords.
      dayOfWeek Specifies an integer in the range 0 to 7; default *. These values correspond to the keywords Sun, Mon, Tue, Wed, Thu, Fri, and Sat, which can be used instead. The values 0 and 7 both correspond to the keyword Sun. When both dayOfMonth and dayOfWeek are a value other than *, only one of the attributes needs to match a given day.
      month Specifies an integer in the range 1 to 12; default *. These values correspond to the keywords Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, and Dec, which can be used instead.
      year Specifies any four-digit calendar year; default *.

      You can specify each of these attributes using an x-y range notation. For example, 0-3 is a valid range for the hour attribute and Jun-Aug is a valid range for the month attribute. Additionally, the second, minute, and hour attributes can be specified using an x/y increment notation. For example, 30/10 is a valid increment for the minute attribute, which includes the values 30, 40, and 50.

      All attributes can also be specified as comma-delimited lists of single values or ranges of values. For example, the value 4,10-12 is valid for the hour attribute, and it corresponds to the times 4 AM, 10 AM, 11 AM, and 12 PM.

      Avoid trouble: When you use the default values of second="0", minute="0", and hour="0", the timer runs one time each day at midnight. If you specify @Schedule(minute="*"), the default values for hour and second still apply, and the timer runs once every minute from 12AM-1AM. If you want the timer to run every minute of every hour, you must specify @Schedule(hour="*", minute="*").

      The following example uses the America/New_York time zone value for its calendar operations. The timer runs on the last Friday of the months January, February, March, and June. On those days, it runs every two hours starting at 1:30 AM:

      TimerService theTimerService = theEJBContext.getTimerService();
      Timer theTimer = theTimerService.createCalendarTimer(new ScheduleExpression()
      	.timezone("America/New_York")
      	.month("Jan-Mar, Jun")
      	.dayOfMonth("Last Fri")
      	.hour("1/2")
      	.minute(30))
  • To create timers automatically, define the timeout callback method using the @Schedule or @Schedules annotation or using the timer deployment descriptor element. Use annotations to write metadata for EJBs inside your source code. For more details, see the information about EJB 3.x metadata annotations.

    A bean can have multiple timeout callback methods for timers that are created automatically. The timeout callback method and automatic timers are identified by the @Schedule or @Schedules annotation in the source code or by using the timer deployment descriptor element in the ejb-jar.xml file. If you specify both annotations for the same method or if you specify an annotation and the timer deployment descriptor element for the same method, the metadata is combined and multiple automatic timers are created. The timeout callback methods must have a void return type and must accept either no parameters or a single parameter of type javax.ejb.Timer. All automatic timers are calendar-based. See information about scheduling calendar-based timers for additional information.

    The server creates automatic timers when the application starts for the first time. Subsequent application start operations detect that timers have already been created for this application, and the timers are not recreated even if they were subsequently canceled. For persistent automatic timers, the server stores this data in the scheduler tables. If your application is installed on a server cluster, then you must configure the EJB container on each server to use a shared cluster-scoped scheduler. If your application is installed on independent servers, then you must ensure that each server is configured with a unique database or unique database table prefix. See information about clustered environment considerations for timer service.

    The application server automatically removes persistent automatic timers from the database when you uninstall the application while the server is running. If the application server is not running, you must manually delete the automatic timers from the database. Additionally, if you add, remove, or change the metadata for automatic timers while the server is not running, you must manually delete the automatic timers.

    • Define the automatic timer by using the @Schedule annotation. The following example uses @Schedule annotation:
      class MyBeanImpl implements MyBean {
          @Schedule(hour="20", info="single timer", persistent=false)
          public void automatic(Timer t) {
              // ...
          }
      }

      The @Schedule annotation has second, minute, hour, dayOfMonth, dayOfWeek, month, year, and timezone elements that correspond to the same attributes of javax.ejb.ScheduleExpression. The annotation also has a persistent element that you can use to specify whether the server uses the EJB timer service scheduler to persist the timer. By default, automatic timers are persistent. Finally, the annotation also has an info element that you can use to specify application information that is delivered as a java.lang.String object with the javax.ejb.Timer object when the timeout callback method runs.

    • Define multiple automatic timers for the same method by using the @Schedules annotation. The following example uses the @Schedules annotation:
      class MyBeanImpl implements MyBean {
          @Schedules(
              @Schedule(hour="1" info="1AM timer", persistent=false),
              @Schedule(minute="0/30" info="30 minute timer")
          )
          public void automaticMultiple(Timer t) {
              // ...
          }
      }
    • Define timers using the deployment descriptor element. You can use the following subelements of the timer element:
      Table 4. Subelements of the timer element. Subelements of the timer element
      Element Required or Optional Description
      schedule Required Includes optional second, minute, hour, day-of-month, day-of-week, month, and year subelements that correspond to the same attributes of javax.ejb.ScheduleExpression.
      start and end Optional Specify the inclusive starting and ending points for calculating timeouts.
      timeout-method Required Specifies the timeout callback method.
      persistent Optional Specifies whether the server uses the EJB timer service scheduler to persist the timer. By default, automatic timers are persistent.
      timezone Optional Corresponds to the same attribute of javax.ejb.ScheduleExpression.
      info Optional Specifies application information that is delivered as a java.lang.String object with the javax.ejb.Timer object when the timeout callback method runs.

      The following example uses the timer deployment descriptor element:

      
          <session>
            <ejb-name>MyBeanImpl</ejb-name>
            <timer>
              <schedule>
                <hour>20</hour>
              </schedule>
              <start>2000-01-01T13:00:00</start>
              <timeout-method>
                <method-name>automatic</method-name>
              </timeout-method>
              <persistent>false</persistent>
              <timezone>America/New_York</timezone>
              <info>single timer</info>
            </timer>
          </session>
  • Determine whether your timer is persistent or non-persistent.
    • Create a persistent timer.
    • Create a non-persistent timer.
  • Deploy your EJB application.
    After you deploy your EJB application, the enterprise bean must run so that the createTimer methods are called before the timer is created programmatically.
    If the timer is automatically created, the timer starts when the EJB application is started.

Results

You have programmatically or automatically configured an EJB timer that is either persistent or non-persistent.