Search code examples
perlmojolicious

Start stop reset timer in perl


Is there a start/stop timer in Perl. I had tried AnyEvent but this is like a one time or recurring timer. Once set, I can reset the timeout interval.

I have a requirement where I have to reset the timer if an event occurs within the timer timeout interval. Is there any Perl module that does this job?

Thanks in advance.


Solution

  • UPDATE

    This question actually prompted quite a bit of discussion on the #mojo IRC channel. The end result is that, barring some unforseen problems, the upcoming Mojolicious 4.0 release will include a new reactor method again which can restart timers. It turns out that this new method (inspired partially by this question) provides a massive performance increase when used internally by Mojolicious in a certain case (high load with high concurrency). Once 4.0 is released, try this updated example version of the second example below:

    #!/usr/bin/env perl
    
    use Mojo::Base -strict;
    use Mojo::IOLoop;
    
    my $loop = Mojo::IOLoop->singleton;
    
    my $now = 1;
    $loop->recurring( 1 => sub { print $now++ . "\n" } );
    
    my $timer = $loop->timer( 3 => \&boom );
    
    $loop->timer( 2 => sub { 
      print "Event resets. No boom yet\n";
      $loop->reactor->again($timer);
    });
    
    $loop->start;
    
    sub boom { 
      print "Boom!\n";
      $loop->stop;
    }
    

    ORIGINAL

    Here is a quick and dirty using the Mojo::IOLoop directly. If this is run inside a server you probably don't need the start and stop methods. Basically the there is a countdown variable which may be reset elsewhere and the recurring timer checks to see if that countdown has expired before it goes boom.

    #!/usr/bin/env perl
    
    use Mojo::Base -strict;
    use Mojo::IOLoop;
    
    my $loop = Mojo::IOLoop->singleton;
    
    my $now = 1;
    my $timeout = 3;
    $loop->recurring( 1 => sub {
      print $now++ . "\n";
      boom() unless $timeout--;
    });
    
    $loop->timer( 2 => sub { 
      print "Event resets. No boom yet\n";
      $timeout = 3;
    });
    
    $loop->start;
    
    sub boom { 
      print "Boom!\n";
      $loop->stop;
    }
    

    The above method is more efficient if you expect that you are going to have many resets. Here is another example which is a less efficient but more direct example. In this case, the idea is to keep the id of the timer so you can remove it and add another. This effectively resets the timer.

    #!/usr/bin/env perl
    
    use Mojo::Base -strict;
    use Mojo::IOLoop;
    
    my $loop = Mojo::IOLoop->singleton;
    
    my $now = 1;
    $loop->recurring( 1 => sub { print $now++ . "\n" } );
    
    my $timer = $loop->timer( 3 => \&boom );
    
    $loop->timer( 2 => sub { 
      print "Event resets. No boom yet\n";
      $loop->remove($timer);
      $timer = $loop->timer( 3 => \&boom );
    });
    
    $loop->start;
    
    sub boom { 
      print "Boom!\n";
      $loop->stop;
    }
    

    Note that the recurring event used here is just to show the elapsed time and isn't important to the flow.