File Coverage

blib/lib/Catmandu/Fix/Bind/timeout.pm
Criterion Covered Total %
statement 31 35 88.5
branch 7 14 50.0
condition 1 2 50.0
subroutine 8 8 100.0
pod 0 3 0.0
total 47 62 75.8


line stmt bran cond sub pod time code
1              
2             use Catmandu::Sane;
3 1     1   884  
  1         2  
  1         6  
4             our $VERSION = '1.2018';
5              
6             use Moo;
7 1     1   16 use Clone ();
  1         2  
  1         6  
8 1     1   382 use Time::HiRes;
  1         1  
  1         28  
9 1     1   6 use namespace::clean;
  1         2  
  1         4  
10 1     1   72  
  1         2  
  1         24  
11             with 'Catmandu::Fix::Bind';
12              
13             has time => (is => 'ro');
14             has units => (is => 'ro', default => sub {'SECONDS'});
15             has sleep => (is => 'rw');
16              
17             my ($self, $data) = @_;
18              
19 17     17 0 53 my $sleep = $self->time;
20             my $units = $self->units // 'SECONDS';
21 17         72  
22 17   50     70 if ($units =~ /^MICROSECOND(S)?$/i) {
23             $sleep /= 1000000;
24 17 50       165 }
    50          
    50          
    0          
    0          
25 0         0 elsif ($units =~ /^MILLISECOND(S)$/i) {
26             $sleep /= 1000;
27             }
28 0         0 elsif ($units =~ /^SECOND(S)?$/i) {
29              
30             # ok
31             }
32             elsif ($units =~ /^MINUTE(S)?$/i) {
33             $sleep *= 60;
34             }
35 0         0 elsif ($units =~ /^HOUR(S)?$/i) {
36             $sleep *= 3600;
37             }
38 0         0 else {
39             # ok - use seconds
40             }
41              
42             $self->sleep($sleep);
43              
44 17         67 [$data, Clone::clone($data)];
45             }
46 17         485  
47             my ($self, $mvar, $func) = @_;
48              
49             my $sleep = $self->sleep();
50              
51             if ($sleep >= 0) {
52             my $start = [Time::HiRes::gettimeofday];
53              
54             $mvar->[0] = $func->($mvar->[0]);
55              
56             $sleep -= Time::HiRes::tv_interval($start);
57              
58             $self->sleep($sleep);
59             }
60              
61             $mvar;
62             }
63              
64             my ($self, $mvar) = @_;
65              
66             if ($self->sleep < 0) {
67             $self->log->warn("timeout after > "
68 15     15 0 43 . $self->time . " "
69             . $self->units . " : "
70 15 100       149 . (-1 * $self->sleep)
71 3         74 . " extra time");
72             inline_replace($mvar->[0], $mvar->[1]);
73             }
74              
75             $self->sleep < 0 ? $mvar->[1] : $mvar->[0];
76 3         306 }
77              
78             my ($old, $new) = @_;
79 15 100       282  
80             for my $key (keys %$old) {
81             delete $old->{$key};
82             }
83 3     3 0 10  
84             for my $key (keys %$new) {
85 3         21 $old->{$key} = $new->{$key};
86 4         17 }
87             }
88              
89 3         18 1;
90 3         14  
91              
92             =pod
93              
94             =head1 NAME
95              
96             Catmandu::Fix::Bind::timeout - run fixes that should run within a time limit
97              
98             =head1 SYNOPSIS
99              
100             # The following bind will run fix1(), fix2(), ... fixN() only if the
101             # action can be done in 5 seconds
102             do timeout(time:5, units:seconds)
103             fix1()
104             fix2()
105             fix3()
106             .
107             .
108             .
109             fixN()
110             end
111              
112             next_fix()
113              
114             =head1 DESCRIPTION
115              
116             The timeout binder will run the supplied block only when all the fixes can be
117             run within a time limit. All fixes (except side-effects) are ignored when the
118             block can't be executed within the time limit.
119              
120             =head1 CONFIGURATION
121              
122             =head2 timeout(time => VALUE , units => MICROSECOND|MILLISECONDS|SECONDS|MINUTES|HOURS)
123              
124             Set a timeout to VALUE. This timeout doesn't prevent a fix script to run longer than the
125             specified value, but it does prevent fixes to have any effect when the timeout has been reached.
126              
127             # This script will run 10 seconds
128             do timeout(time:5, units:seconds)
129             add_field(foo,ok) # This will be ignored
130             sleep(10,seconds)
131             set_field(foo,error) # This will be ignored
132             end
133              
134             At timeout a log message of level WARN will be generated.
135              
136             =head1 SEE ALSO
137              
138             L<Catmandu::Fix::Bind>
139              
140             =cut