File Coverage

lib/Data/Valve.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             # $Id: /mirror/coderepos/lang/perl/Data-Valve/trunk/lib/Data/Valve.pm 87019 2008-10-02T02:11:03.080140Z daisuke $
2              
3             package Data::Valve;
4 1     1   2836 use Moose;
  0            
  0            
5             use Data::Valve::Bucket;
6             use Scalar::Util ();
7              
8             use XSLoader;
9             our $VERSION = '0.00010';
10             our $AUTHORITY = 'cpan:DMAKI';
11              
12             XSLoader::load __PACKAGE__, $VERSION;
13              
14             has 'max_items' => (
15             is => 'rw',
16             isa => 'Int',
17             required => 1
18             );
19              
20             has 'interval' => (
21             is => 'rw',
22             isa => 'Num',
23             required => 1
24             );
25              
26             has 'strict_interval' => (
27             is => 'rw',
28             isa => 'Bool',
29             required => 1,
30             default => 0
31             );
32              
33             has '__bucket_store' => (
34             accessor => 'bucket_store',
35             is => 'rw',
36             does => 'Data::Valve::BucketStore',
37             required => 1,
38             );
39              
40             __PACKAGE__->meta->make_immutable;
41              
42             no Moose;
43              
44             sub BUILDARGS {
45             my ($self, %args) = @_;
46              
47             my $store = delete $args{bucket_store} || { module => 'Memory' };
48             if (! Scalar::Util::blessed($store) ) {
49             my $module = $store->{module};
50             if ($module !~ s/^\+//) {
51             $module = "Data::Valve::BucketStore::$module";
52             }
53             Class::MOP::load_class($module);
54              
55             $store = $module->new( %{ $store->{args} } );
56             }
57              
58             if ($args{strict_interval}) {
59             # in strict_interval mode, max_items doesn't mean anything
60             $args{max_items} = 0;
61             }
62              
63             return { %args, __bucket_store => $store };
64             }
65              
66             sub BUILD {
67             my $self = shift;
68             $self->bucket_store->context($self);
69             }
70              
71             sub try_push {
72             my ($self, %args) = @_;
73             $args{key} ||= '__default';
74             $self->bucket_store->try_push(%args);
75             }
76              
77             sub reset {
78             my ($self, %args) = @_;
79             $args{key} ||= '__default';
80             $self->bucket_store->reset(%args);
81             }
82              
83             sub fill {
84             my ($self, %args) = @_;
85             $args{key} ||= '__default';
86             $self->bucket_store->fill(%args);
87             }
88              
89             1;
90              
91             __END__
92              
93             =head1 NAME
94              
95             Data::Valve - Throttle Your Data
96              
97             =head1 SYNOPSIS
98              
99             use Data::Valve;
100              
101             my $valve = Data::Valve->new(
102             max_items => 10,
103             interval => 30
104             );
105              
106             if ($valve->try_push()) {
107             print "ok\n";
108             } else {
109             print "throttled\n";
110             }
111              
112             if ($valve->try_push(key => "foo")) {
113             print "ok\n";
114             } else {
115             print "throttled\n";
116             }
117              
118             =head1 DESCRIPTION
119              
120             Data::Valve is a throttler based on Data::Throttler. The underlying throttling
121             mechanism is much simpler than Data::Throttler, and so is faster.
122              
123             It also comes with Memcached support for a distributed throttling via
124             memcached + keyedmutexd. This means that you can have multiple hosts throttling
125             on the same "key". For example, multiple crawler instances can throttle
126             requests against a single host safely. To enable distributed throttling,
127             you simply need to specify a Data::Valve::BucketStore instance that supports
128             distribution (i.e. Data::Valve::BucketStore::Memcached) or create your own
129             instance, and pass it to the constructor:
130              
131             Data::Valve->new(
132             ...,
133             bucket_store => {
134             module => "Memcached", # to use Data::Valve::BucketStore::Memcached
135             args => {
136             servers => [ '127.0.0.1:11211' ]
137             }
138             }
139             );
140              
141             Please note that for distributed throttling to work, you must specify the
142             correct values in max_items, interval, and so forth, for each Data::Valve
143             instance. Data::Valve will not try to automatically adjust this for you.
144             You must coordinate it in the client side (i.e., whatever that's using
145             Data::Valve)
146              
147             Since version 0.00006, Data::Valve supports "strict_interval" mode, where
148             instead of counting the number of items over a range of time, it simply
149             calculates the amount of time elapsed since the last logged request.
150              
151             To enable, specify it in the constrctor:
152              
153             # This specifies that at least 5 seconds should have passed before
154             # the next item can go
155             Data::Valve->new(
156             interval => 5,
157             strict_interval => 1,
158             );
159              
160             =head1 METHODS
161              
162             =head2 new(%args)
163              
164             =over 4
165              
166             =item max_items
167              
168             In strict interval mode, does not mean anything. If NOT in strict interval
169             mode, specifies the max number of items that can go through this throttler
170             in the given interval.
171              
172             =item interval
173              
174             In strict interval mode, this specifies the number of seconds to wait between
175             each request. If NOT in strict interval mode, specifies the number of seconds
176             to span the requests, up to the value specified in max_items
177              
178             C<interval> may be a fractional number, denoting fractional seconds.
179              
180             =item strict_interval
181              
182             Boolean. Enable/Disable strict interval mode. Default is off.
183              
184             =back
185              
186             =head2 fill([key => $key_name])
187              
188             Fills up the specified bucket until it starts throttling
189              
190             =head2 reset([key => $key_name])
191              
192             Clears the specified bucket so the next request will succeed for sure
193              
194             =head2 try_push([key => $key_name])
195              
196             =head1 AUTHOR
197              
198             Daisuke Maki C<< <daisuke@endeworks.jp> >>
199              
200             =head1 LICENSE
201              
202             This program is free software; you can redistribute it and/or modify it
203             under the same terms as Perl itself.
204              
205             See http://www.perl.com/perl/misc/Artistic.html
206              
207             =cut