File Coverage

blib/lib/Starch/Plugin/TimeoutStore.pm
Criterion Covered Total %
statement 18 18 100.0
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 24 24 100.0


line stmt bran cond sub pod time code
1             package Starch::Plugin::TimeoutStore;
2              
3             $Starch::Plugin::TimeoutStore::VERSION = '0.07';
4              
5             =head1 NAME
6              
7             Starch::Plugin::TimeoutStore - Throw an exception if store access surpass a timeout.
8              
9             =head1 SYNOPSIS
10              
11             my $starch = Starch->new(
12             plugins => ['::TimeoutStore'],
13             store => {
14             class => '::Memory',
15             timeout => 0.1, # 1/10th of a second
16             },
17             ...,
18             );
19              
20             =head1 DESCRIPTION
21              
22             This plugin causes all calls to C, C, and C to throw
23             an exception if they surpass a timeout period.
24              
25             The timeout is implemented using L.
26              
27             Note that some stores implement timeouts themselves and their native
28             may be better than this naive implementation.
29              
30             The whole point of detecting timeouts is so that you can still serve
31             a web page even if the underlying store backend is failing, so
32             using this plugin with L is
33             probably a good idea.
34              
35             =cut
36              
37 1     1   4831 use Types::Common::Numeric -types;
  1         2  
  1         18  
38 1     1   1312 use Starch::Util qw( croak );
  1         2  
  1         58  
39 1     1   513 use Sys::SigAction qw( timeout_call );
  1         6632  
  1         74  
40              
41 1     1   8 use Moo::Role;
  1         2  
  1         12  
42 1     1   430 use strictures 2;
  1         10  
  1         39  
43 1     1   211 use namespace::clean;
  1         2  
  1         9  
44              
45             with qw(
46             Starch::Plugin::ForStore
47             );
48              
49             =head1 OPTIONAL STORE ARGUMENTS
50              
51             These arguments are added to classes which consume the
52             L role.
53              
54             =head2 timeout
55              
56             How many seconds to timeout. Fractional seconds may be passed, but
57             may not be supported on all systems (see L).
58             Set to C<0> to disable timeout checking. Defaults to C<0>.
59              
60             =cut
61              
62             has timeout => (
63             is => 'ro',
64             isa => PositiveOrZeroNum,
65             default => 0,
66             );
67              
68             foreach my $method (qw( set get remove )) {
69             around $method => sub{
70             my $orig = shift;
71             my $self = shift;
72              
73             local $Carp::Internal{ (__PACKAGE__) } = 1;
74              
75             my $timeout = $self->timeout();
76             return $self->$orig( @_ ) if $timeout == 0;
77              
78             my @args = @_;
79             my $data;
80              
81             if ( timeout_call( $timeout, sub{
82             $data = $self->$orig( @args );
83             }) ) {
84             croak sprintf(
85             'The %s method %s exceeded the timeout of %s seconds',
86             $self->short_class_name(), $method, $timeout,
87             );
88             }
89              
90             return $data if $method eq 'get';
91             return;
92             };
93             }
94              
95             1;
96             __END__