Apama 10.15.0 | Developing Apama Applications | Developing Apama Applications in EPL | Defining Event Listeners | Understanding time in the correlator | About timers and their trigger times
 
About timers and their trigger times
In an event expression, when you specify the within, wait, or at operator you are specifying a timer. Every timer has a trigger time. The trigger time is when you want the timer to fire.
*When you use the within operator, the trigger time is when the specified length of time elapses. If a within timer fires, the event listener fails. In the following event listener, the trigger time is 30 seconds after A becomes true.
on A -> B within(30.0) notifyUser();
If B becomes true within 30 seconds after the event listener detects an A, the trigger time is not reached, the timer does not fire, and the monitor calls the notifyUser() action. If B does not become true within 30 seconds after the event listener detects an A, the trigger time is reached, the timer fires, and the event listener fails. The monitor does not call notifyUser(). The correlator subsequently terminates the event listener since it can never trigger.
*When you use the wait operator, the trigger time is when the specified pause during processing of the event expression has elapsed. When a wait timer fires, processing continues. In the following expression, the trigger time is 20 seconds after A becomes true. When the trigger time is reached, the timer fires. The event listener then starts watching for B. When B is true, the monitor calls the success action.
on A -> wait(20.0) -> B success();
*When you use the at operator, the trigger time is one or more specific times. An at timer fires at the specified times. In the following expression, the trigger time is five minutes past each hour every day. This timer fires 24 times each day. When the timer fires, the monitor calls the success action.
on all at(5, *, *, *, *) success();
Important: 
Triggering using the at operator always uses the time zone in which the correlator is running.
At each clock tick, the correlator evaluates each timer to determine whether that timer's trigger time has been reached. If a timer's trigger time has been reached, the correlator fires that timer. When a timer's trigger time is exactly at the same time as a clock tick, the timer fires at its exact trigger time. When a timer's trigger time is not exactly at the same time as a clock tick, the timer fires at the next clock tick. This means that if a timer's trigger time is .01 seconds after a clock tick, that timer does not fire until .09 seconds later.
When a timer fires, the current time is always the trigger time of the timer. This is regardless of whether the timer fired at its trigger time or at the first clock tick after its trigger time. In other words, the current time is equal to the value of the currentTime variable when the timer was started plus the elapsed wait time. For example:
float listenerSetupTime := currentTime;
on wait(1.23) {
   //When the timer fires, currentTime = (listenerSetupTime + 1.23)
}
A single clock tick can make a repeating timer fire multiple times. For example, if you specify on all wait(0.01), this timer fires 10 times every tenth of a second.
Because of rounding constraints,
*A timer such as on all wait(0.1) drifts away from firing every tenth of a second. The drift is of the order of milliseconds per century, but you can notice the drift if you convert the value of the currentTime variable to a string.
*Two timers that you might expect to fire at the same instant might fire at different, though very close, times.
The rounding constraint is that you cannot accurately express 0.1 seconds as a float because you cannot represent it in binary notation. For example, the on wait(0.1) event listener waits for 0.10000000000000000555 seconds.
To specify a timer that fires exactly 10 times per second, calculate the length of time to wait by using a method that does not accumulate rounding errors. For example, calculate a whole part and a fractional part:
monitor TenTimesPerSecondMonitor { 
   // Use integers to keep track of the next timer fire time.
   // This ensures that the value of the currentTime variable increases
   // by exactly 1.0 after every 10 tenths of a second.
   integer nextFireTimeInteger;
   integer nextFireTimeFraction;
   action onload() {
     nextFireTimeInteger := currentTime.ceil();
     nextFireTimeFraction := (10.0 *
       (currentTime-nextFireTimeInteger.toFloat() ) ).ceil();
     setupTimeListener();
   }
 
  action setupTimeListener() {
    nextFireTimeFraction := nextFireTimeFraction + 1;
    if(nextFireTimeFraction = 10) {
      nextFireTimeFraction := 0;
      nextFireTimeInteger := nextFireTimeInteger+1;
    }
    on wait( (nextFireTimeInteger.toFloat() +
      (nextFireTimeFraction.toFloat()/10.0) ) - currentTime )
    {
      setupTimeListener();
      doWork();
    }
  }
 
   action doWork()
   {
     // This is called 10 times every second.
     log currentTime.toString();
     // ...
   }
}
When a timer fires, the correlator processes items in the following order. The correlator:
1. Triggers all event listeners that trigger at the same time.
2. Routes any events, and routes any events that those events route, and so on.
3. Fires any timers at the next trigger time.