Doing things every now and then is a common task, especially in programs that run for a long time. Some examples: reporting on a program's status, flushing something to disk, polling something to see if it has changed, or monitoring or starting processes à la cron(8).

POE::Kernel's delay() method makes short work of a periodic task. Simply call it again from the delayed event's handler.

#!/usr/bin/perl -w

use strict;
use POE;

use Time::HiRes qw(time);

POE::Session->create(
  inline_states => {
    _start => sub {
      $_[KERNEL]->delay(tick => 1);
    },

    tick => sub {
      print "tick at ", time(), "\n";
      $_[KERNEL]->delay(tick => 1);
    },
  },
);

POE::Kernel->run();
exit 0;

Here's what the program displays as it runs:

  tick at 1005345715.2626
  tick at 1005345716.27214
  tick at 1005345717.28219
  tick at 1005345718.2922
  tick at 1005345719.30226
  tick at 1005345720.31235
  tick at 1005345721.32225
  tick at 1005345722.33228

On an Athlon 1GHz, POE's overhead adds about 1/100 second to the "tick" event's interval. This delay will vary according to a system's processor speed, operating system, and load.

That 1/100 second may be insignificant for most programs, but it equates to a loss of about 15 minutes per day. The loss is inversely proportional to the delay period.

  Delay      Daily loss
  ========== ====================
  1 second   about 14 1/2 minutes
  1 minute   about 14 1/3 seconds
  1 hour     about 1/4 second

The loss can be avoided altogether by keeping track of the next alarm time and using alarm() instead of delay. POE's overhead will still cause some latency between the ideal event time and the actual dispatch time, but the following program compensates for it.

This one-second timer program keeps the next alarm time in the HEAP and sets an absolute alarm for that time. Since the next alarm time increases in a constant fashion, so does the dispatch time.

#!/usr/bin/perl -w

use strict;
use POE;

use Time::HiRes qw(time);

POE::Session->create(
  inline_states => {
    _start => sub {
      $_[HEAP]->{next_alarm_time} = int(time()) + 1;
      $_[KERNEL]->alarm(tick => $_[HEAP]->{next_alarm_time});
    },

    tick => sub {
      print "tick at ", time(), "\n";
      $_[HEAP]->{next_alarm_time}++;
      $_[KERNEL]->alarm(tick => $_[HEAP]->{next_alarm_time});
    },
  },
);

POE::Kernel->run();
exit 0;

The corresponding runtime output shows a 1/100 to 1/50 second lag between each alarm's due time and the actual dispatch time, but the average interval between events is 1 second.

  tick at 1005346468.01947
  tick at 1005346469.01953
  tick at 1005346470.01965
  tick at 1005346471.01977
  tick at 1005346472.0099
  tick at 1005346473.01008
  tick at 1005346474.01015
  tick at 1005346475.01025

For more advanced recurring alarms, see [POE::Component::Schedule] and [POE::Component::Cron].