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   1422  
  1         2  
  1         10  
4             our $VERSION = '1.2019';
5              
6             use Moo;
7 1     1   9 use Clone ();
  1         1  
  1         9  
8 1     1   434 use Time::HiRes;
  1         2  
  1         16  
9 1     1   5 use namespace::clean;
  1         3  
  1         10  
10 1     1   81  
  1         2  
  1         45  
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 122 my $sleep = $self->time;
20             my $units = $self->units // 'SECONDS';
21 17         77  
22 17   50     70 if ($units =~ /^MICROSECOND(S)?$/i) {
23             $sleep /= 1000000;
24 17 50       157 }
    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         81 [$data, Clone::clone($data)];
45             }
46 17         432  
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 51 . $self->time . " "
69             . $self->units . " : "
70 15 100       69 . (-1 * $self->sleep)
71 3         123 . " extra time");
72             inline_replace($mvar->[0], $mvar->[1]);
73             }
74              
75             $self->sleep < 0 ? $mvar->[1] : $mvar->[0];
76 3         324 }
77              
78             my ($old, $new) = @_;
79 15 100       312  
80             for my $key (keys %$old) {
81             delete $old->{$key};
82             }
83 3     3 0 13  
84             for my $key (keys %$new) {
85 3         21 $old->{$key} = $new->{$key};
86 4         20 }
87             }
88              
89 3         20 1;
90 3         28  
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