File Coverage

blib/lib/Util/Timeout.pm
Criterion Covered Total %
statement 13 13 100.0
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 18 100.0


line stmt bran cond sub pod time code
1 1     1   101407 use strict;
  1         2  
  1         36  
2 1     1   5 use warnings;
  1         1  
  1         48  
3             package Util::Timeout;
4             BEGIN {
5 1     1   68 $Util::Timeout::VERSION = '0.01';
6             }
7 1     1   871 use POSIX qw{ceil};
  1         7467  
  1         7  
8 1     1   2051 use Exporter::Declare qw{-magic};
  1         25279  
  1         5  
9             use Sys::SigAction qw{timeout_call};
10             use Devel::Declare::Parser::Sublike;
11              
12             # ABSTRACT: thin wrapper around Sys::SigAction::timeout_call
13              
14             =head1 SYNOPSIS
15              
16             use Util::Timeout;
17             timeout $seconds { ... } or do { ... };
18              
19             retry $times { ... } or do { ... };
20              
21             =head1 DESCRIPTION
22              
23             Sys::SigAction::timeout_call sets a timer for $seconds, if your code block is still running when the
24             timer trips then it is killed off. timeout then returns a false value thus you can chain with 'or'
25             to allow for a clean syntaticaly correct syntax
26              
27             =head1 FUNCTIONS
28              
29             =head2 timeout
30              
31             timeout 1 { sleep(2) } or do { $error = 'timed out' };
32              
33             REMEMBER: these are lexical blocks (like eval) so any vars that you want to use else where will
34             need to be scoped as such.
35              
36             Also note, due to alarm not allowing for decimal numbers, all values are rounded up. Any value given
37             for $seconds that is <= 0 will shortcut and your code block will not be executed and 0 returned.
38              
39             =cut
40              
41             default_export timeout sublike {
42             my ($seconds, $code) = @_;
43             $seconds = ceil($seconds);
44             return 0 unless $seconds > 0;
45             return 0 unless defined $code && ref($code) eq 'CODE';
46             # invert return to allow the use of 'or'
47             !timeout_call( $seconds, $code ); # 0 => timed out
48             }
49              
50             =head2 retry
51              
52             my $num = 3;
53             retry 5 { timeout 1 { sleep( $num-- ) } } or do { $error = 'timed out 5 times' };
54              
55             retry will run your the code block, if the block returns true then we stop running and return '1'.
56             If your code block returns false then it is run again, up to $times number of times (5 in the
57             exampele), in this case rerun returns '0' allowing you to use 'or' like with timeout.
58              
59             $times is expeceted to be an int, any decimal value will be rounded up. If $times is <= 1 then
60             your code block will not be run and 0 will be returned;
61              
62             =cut
63              
64             default_export retry sublike {
65             my ($times, $code) = @_;
66             $times = ceil($times);
67             return 0 unless $times >= 1;
68             for (1..$times) {
69             return 1 if &$code;
70             }
71             return 0;
72             }
73              
74             1;