File Coverage

blib/lib/HTTP/MultiGet.pm
Criterion Covered Total %
statement 168 281 59.7
branch 23 64 35.9
condition 4 12 33.3
subroutine 35 43 81.4
pod 15 20 75.0
total 245 420 58.3


line stmt bran cond sub pod time code
1             package HTTP::MultiGet;
2              
3             =head1 NAME
4              
5             HTTP::MultiGet - Run many http requests at once!
6              
7             =head1 SYNOPSIS
8              
9             use Modern::Perl;
10             use HTTP::MultiGet;
11             use HTTP::Request;
12              
13             my $getter=new HTTP::MultiGet;
14              
15             my @requests=(map { HTTP::Request->new(GET=>"http://localhost$_") } (1 .. 1000));
16             my @responses=$getter->run_requests(@requests);
17              
18             my $id=0;
19             foreach my $response (@responses) {
20             my $request=$requests[$id++];
21             print "Results for: ".$request->uri."\n";
22             if($response->is_success) {
23             print $response->decoded_content;
24             } else {
25             print $response->status_line,"\n";
26             }
27             }
28              
29              
30             =head2 Handling Multiple Large Downloads
31              
32             use Modern::Perl;
33             use HTTP::MultiGet;
34             use HTTP::Request;
35              
36             my $req=HTTP::Request->new(GET=>'http://some.realy.big/file/to/download.gz');
37             my $req_b=HTTP::Request->new(GET=>'http://some.realy.big/file/to/download2.gz');
38              
39             # create a callback
40             my $code=sub {
41             my ($getter,$request,$headers,$chunk)=@_;
42             # 0: Current HTTP::MultiGet instance
43             # 1: HTTP::Request object
44             # 2: HTTP::Headers object
45             # 3: Chunk of data being downloaded
46             if($headers->header('Status')==200) {
47             # do something
48             } else {
49             # do something with $body
50             }
51             };
52             my $getter=new HTTP::MultiGet;
53             my ($result,$result_b)=$getter->run_requests([$req,on_body=>$code],[$req_b,on_body=>$code]);
54              
55              
56             The arguments: on_body=>$code are called called on each chunk downloaded. $result is created when the download is completed, but $result->decoded_content is going to be empty
57              
58             =head1 DESCRIPTION
59              
60             Created a wrapper for: L<AnyEvent::HTTP>, but provides a more LWP like feel.
61              
62             =cut
63              
64 6     6   620292 use Moo;
  6         5655  
  6         35  
65 6     6   1942 use Log::Log4perl;
  6         18  
  6         62  
66 6     6   2966 use Data::Queue;
  6         156313  
  6         225  
67 6     6   52 use Scalar::Util qw(looks_like_number);
  6         13  
  6         369  
68             Log::Log4perl->wrapper_register(__PACKAGE__);
69 6     6   39 use AnyEvent;
  6         14  
  6         189  
70 6     6   33 use Data::Dumper;
  6         13  
  6         277  
71 6     6   530 use HTTP::Response;
  6         22652  
  6         153  
72 6     6   35 use HTTP::Headers;
  6         14  
  6         135  
73 6     6   492 use HTTP::Request;
  6         1008  
  6         166  
74 6     6   42 use Class::Method::Modifiers;
  6         17  
  6         400  
75 6     6   2815 use AnyEvent::HTTP::Request;
  6         11567  
  6         205  
76 6     6   55 use MooX::Types::MooseLike::Base qw(:all);
  6         34  
  6         1953  
77 6     6   2661 use AnyEvent::HTTP::Response;
  6         3962  
  6         158  
78 6     6   74 use AnyEvent;
  6         17  
  6         142  
79 6     6   33 use Carp qw(croak);
  6         12  
  6         307  
80 6     6   36 use Ref::Util qw(is_plain_arrayref is_plain_hashref);
  6         13  
  6         300  
81             require AnyEvent::HTTP;
82 6     6   38 use namespace::clean;
  6         10  
  6         43  
83             BEGIN {
84 6     6   4814 with 'Log::LogMethods';
85 6         11849 with 'Data::Result::Moo';
86             }
87             our $VERSION='1.021';
88              
89             sub BUILD {
90 6     6 0 68 my ($self)=@_;
91              
92 6         71 $self->{stack}=new Data::Queue;
93 6         4164 $self->{que_count}=0;
94 6         38 $self->{que_id}=0;
95             }
96              
97             =head1 Moo Stuff
98              
99             This is a Moo class the object constructor takes the following arguments, along with the following roles
100              
101             Role List:
102              
103             Log::LogMethods
104             Data:::Result::Moo
105              
106             Arguemnts and object accessors:
107              
108             logger: DOES(Log::Log4perl::Logger)
109             request_opts: See AnyEvent::HTTP params for details
110             timeout: Global timeout for everything ( default 300 )
111             max_que_count: How many requests to run at once ( default 20 )
112             max_retry: How many times to retry if we get a connection/negotiation error
113              
114             For internal use only:
115              
116             in_control_loop: true when in the control loop
117             stack: Data::Queue object
118             que_count: Total Number of elements active in the que
119             retry: Anonymous hash used to map ids to retry counts
120              
121             =head2 UNIT TESTING
122              
123             For Unit testing
124              
125             on_create_request_cb: Anonymous code ref to be called
126             when a new request object has been created
127             sub { my ($id,$request)=@_ }
128              
129             Arguments for the call back
130              
131             id: number for the object
132             req: a new instance of $self->SENDER_CLASS
133              
134             Interal blocking control variables
135              
136             loop_control: AnyEvent->condvar object
137             false_id: internal false id tracker
138             fake_jobs: Internal object for handling fake results
139              
140             =cut
141              
142             has false_id=>(
143             is=>'rw',
144             isa=>Int,
145             default=>-1,
146             lazy=>1,
147             );
148              
149             has fake_jobs=>(
150             isa=>HashRef,
151             is=>'rw',
152             default=>sub { {}}
153             );
154              
155             has loop_control=>(
156             is=>'rw',
157             required=>0.
158             );
159              
160             has loop_id=>(
161             is=>'rw',
162             isa=>Num,
163             default=>0,
164             );
165              
166             has max_retry=>(
167             is=>'rw',
168             isa=>Num,
169             default=>3,
170             );
171              
172             has retry=>(
173             is=>'rw',
174             default=>sub { { } },
175             lazy=>1,
176             );
177              
178             has no_more_after =>(
179             is=>'rw',
180             isa=>Num,
181             default=>0,
182              
183             );
184              
185             has on_create_request_cb=>(
186             is=>'rw',
187             isa=>CodeRef,
188             default=>sub { sub { } },
189             lazy=>1,
190             );
191              
192             has in_control_loop=>(
193             is=>'rw',
194             isa=>Bool,
195             default=>0,
196             );
197              
198             has running=>(
199             is=>'ro',
200             default=>sub { {}},
201             lazy=>1,
202             );
203              
204             has request_opts=>(
205             is=>'rw',
206             requires=>1,
207             default=>sub { {cookie_jar=>{},persistent=>0} },
208             );
209              
210             has stack=>( is=>'ro');
211              
212             has results=>(
213             is=>'ro',
214             lazy=>1,
215             default=>sub { {} },
216             );
217              
218             has que_count=>(
219             is=>'rw',
220             isa=>Num,
221             );
222              
223             has timeout =>(
224             is=>'rw',
225             isa=>sub {
226             my $timeout=$_[0];
227             croak 'timeout is a required option' unless looks_like_number($timeout);
228             croak 'timeout must be greater than 0' if $timeout <=0;
229             $timeout,
230             },
231              
232             default=>300,
233             );
234              
235              
236             has max_que_count=> (
237             is=>'rw',
238             isa=>Num,
239             default=>20,
240             );
241              
242              
243             around max_que_count=>sub {
244             my ($org,$self,$count)=@_;
245             if(looks_like_number($count)) {
246             $AnyEvent::HTTP::MAX_PER_HOST=$count if $AnyEvent::HTTP::MAX_PER_HOST < $count;
247             return $org->($self,$count);
248             } else {
249             shift;
250             return $org->(@_);
251             }
252             };
253              
254             =head1 Class constants
255              
256             =over 4
257              
258             =item * my $class=$self->RESPONSE_CLASS
259              
260             Returns the http response class, typically AnyEvent::HTTP::Response.
261              
262             =cut
263              
264 6     6   8289 use constant RESPONSE_CLASS=>'AnyEvent::HTTP::Response';
  6         13  
  6         506  
265              
266             =item * my $class=$self->HEADER_CLASS
267              
268             Returns the header class, typically HTTP::Headers.
269              
270             =back
271              
272             =cut
273              
274 6     6   42 use constant HEADER_CLASS=>'HTTP::Headers';
  6         29  
  6         12828  
275              
276              
277             =head1 OO Methods
278              
279             =over 4
280              
281             =item * my $id=$self->next_que_id
282              
283             Returns the next id.
284              
285             =cut
286              
287             sub next_que_id {
288 2     2 1 5 return $_[0]->{que_id} +=1;
289             }
290              
291             sub running_count {
292 0     0 0 0 my ($self)=@_;
293 0         0 return scalar(keys %{$self->running});
  0         0  
294             }
295              
296             =item * my @ids=$self->add(@requests)
297              
298             Adds @requests to the stack, @ids relates as id=>request
299              
300             =item * my @ids=$self->add([$request,key=>value]);
301              
302             Wrapping [$request] allows passing additional key value to L<AnyEvent::HTTP::Request>, with one exception, on_body=>$code is wrapped an additional callback.
303              
304             =cut
305              
306             sub add {
307 2     2 1 6 my ($self,@list)=@_;
308 2         5 my @ids;
309              
310 2         4 foreach my $req (@list) {
311 2         9 my $id=$self->next_que_id;
312 2         6 push @ids,$id;
313 2         8 $self->add_by_id($id=>$req);
314             }
315 2         9 return @ids;
316             }
317              
318             =item * my $id=$self->add_by_id($id=>$request);
319              
320             Adds the request with an explicit id.
321              
322             =cut
323              
324             sub add_by_id {
325 2     2 1 6 my ($self,$id,$request)=@_;
326 2         8 my $req=$self->create_request($request,$id);
327 2         18 $self->stack->add_by_id($id,$req);
328 2 50       120 $self->retry->{$id}=$self->max_retry unless exists $self->retry->{$id};
329 2         105 $self->on_create_request_cb->($id,$req);
330 2         132 return $id;
331             }
332              
333             =item * $self->run_fake_jobs
334              
335             Runs all current fake jobs
336              
337             =cut
338              
339             sub run_fake_jobs {
340 26     26 1 45 my ($self)=@_;
341            
342 26         62 while($self->has_fake_jobs) {
343 15         320 my $fj=$self->fake_jobs;
344 15         298 $self->fake_jobs({});
345 15         558 while(my (undef,$job)=each (%{$fj})) {
  39         4807  
346 24         59 $job->();
347             }
348             }
349             }
350              
351             =item * $self->run_next
352              
353             Internal functoin, used to run the next request from the stack.
354              
355             =cut
356              
357             sub run_next {
358 20     20 1 110 my ($self)=@_;
359              
360 20         55 $self->run_fake_jobs;
361 20 50       576 return if $self->{que_count} >= $self->max_que_count;
362              
363 20   33     465 while($self->{que_count} < $self->max_que_count and $self->stack->has_next) {
364 0         0 my ($id,$next)=$self->stack->get_next;
365 0         0 $self->running->{$id}=$next;
366 0         0 $next->send;
367 0         0 ++$self->{que_count};
368 0         0 $self->log_debug("Total of: $self->{que_count} running");
369             }
370              
371 20         9751 return 1;
372             }
373              
374             =item * my $id=$self->add_result($cb)
375              
376             Internal function, added for L<HTTP::MultiGet::Role>
377              
378             =cut
379              
380             sub add_result {
381 24     24 1 3616 my ($self,$cb)=@_;
382 24         443 my $current=$self->false_id;
383 24         248 $current -=1;
384 24         366 $self->false_id($current);
385 24         1252 $self->fake_jobs->{$current}=$cb;
386 24         177 return $current;
387             }
388              
389             =item * if($self->has_fake_jobs) { ... }
390              
391             Checks if any fake jobs exist
392              
393             =cut
394              
395             sub has_fake_jobs {
396 41     41 0 60 return 0 < keys %{$_[0]->fake_jobs}
  41         705  
397             }
398              
399             =item * my $result=$self->has_request($id)
400              
401             Returns a Charter::Result Object.
402              
403             When true it contains a string showing where that id is in the list.
404              
405             Values are:
406              
407             complete: Has finished running
408             running: The request has been sent, waiting on the response
409             in_que: The request has not been run yet
410              
411             =cut
412              
413             sub has_request {
414 0     0 1 0 my ($self,$id)=@_;
415              
416 0         0 my $result=$self->new_false('request does not exist!');
417              
418 0 0       0 if(exists $self->results->{$id}) {
    0          
    0          
419 0         0 $result=$self->new_true('complete');
420              
421             } elsif(exists $self->running->{$id}) {
422 0         0 $result=$self->new_true('running');
423              
424             } elsif( $self->stack->has_id($id) ) {
425              
426 0         0 $result=$self->new_true('in_que');
427             }
428            
429 0         0 return $result;
430             }
431              
432             =item * if($self->has_running_or_pending) { ... }
433              
434             Returns a Charter::Result object
435              
436             true: it contains how many objects are not yet complete.
437             false: no incomplete jobs exist
438              
439             =cut
440              
441             sub has_running_or_pending {
442 0     0 0 0 my ($self)=@_;
443 0         0 my $total=$self->stack->total;
444 0         0 $total +=$self->running_count;
445 0 0       0 return $self->new_true($total) if $total >0;
446 0         0 return $self->new_false("there are no objects running");
447             }
448              
449             =item * if($self->has_any) { ... }
450              
451             Returns a Charter::Result object
452              
453             true: conains how many total jobs of any state there are
454             false: there are no jobs in any state
455              
456             =cut
457              
458             sub has_any {
459 0     0 0 0 my ($self)=@_;
460 0         0 my $total=$self->stack->total;
461 0         0 $total +=keys %{$self->running};
  0         0  
462 0         0 $total +=keys %{$self->results};
  0         0  
463              
464 0 0       0 return $self->new_true($total) if $total >0;
465 0         0 return $self->new_false("there are no objects running");
466             }
467              
468             =item * my $result=$self->block_for_ids(@ids)
469              
470             Returns a Charter::Result object
471              
472             when true: some results were found
473              
474             while(my ($id,$result)=each %{$result->get_data}) {
475             if($result) {
476             my $response=$result->get_data;
477             print "Got response: $id, code was: ",$response->code,"\n";
478             } else {
479             print "Failed to get: $id error was: $result\n";
480             }
481             }
482              
483             =cut
484              
485             sub block_for_ids {
486 6     6 1 18 my ($self,@ids)=@_;
487              
488 6         17 $self->run_fake_jobs;
489 6         50 my $results={};
490              
491 6         11 my @check;
492              
493 6         10 my $ok=0;
494 6         14 foreach my $id (@ids) {
495 6 100       141 if(exists $self->results->{$id}) {
    50          
    50          
496             # the result is done
497 2         49 $results->{$id}=$self->results->{$id};
498 2         44 delete $self->results->{$id};
499 2         15 ++$ok;
500              
501             } elsif(exists $self->running->{$id}) {
502              
503 0         0 push @check,$id;
504 0         0 $results->{$id}=$self->new_false('Request Timed out');
505              
506             } elsif( $self->stack->has_id($id) ) {
507              
508 0         0 push @check,$id;
509 0         0 $results->{$id}=$self->new_false('Request Never made it to the que');
510              
511             } else {
512              
513 4         1132 push @check,$id;
514 4         30 $results->{$id}=$self->new_false('request does not exist!');
515             }
516             }
517              
518 6         1244 $self->block_loop;
519 6         2449 foreach my $id (@check) {
520 4 50       66 next unless exists $self->results->{$id};
521              
522 0         0 ++$ok;
523              
524 0         0 $results->{$id}=$self->results->{$id};
525 0         0 delete $self->results->{$id};
526             }
527              
528 6         41 delete @{$self->retry}{@ids};
  6         106  
529 6 100       47 return $self->new_true($results) if $ok!=0;
530 4         12 return $self->new_false("Request(s) timed out");
531             }
532              
533             =item * my $class=$self->SENDER_CLASS
534              
535             $class is the class used to send requests.
536              
537             =cut
538              
539 2     2 1 17 sub SENDER_CLASS { 'AnyEvent::HTTP::Request' }
540              
541             =item * my $req=$self->create_request($req,$id)
542              
543             Internal method. Returns a new instance of $self->SENDER_CLASS for Teh given $request and $id.
544              
545             =cut
546              
547             sub create_request {
548 2     2 1 5 my ($self,$obj,$id)=@_;
549            
550 2         4 my $req;
551             my $opt={
552 2         3 params=>{%{$self->request_opts}},
  2         17  
553             };
554 2 50       7 if(is_plain_arrayref($obj)) {
555 0         0 my @args;
556 0         0 ($req,@args)=@{$obj};
  0         0  
557 0         0 my $code=$self->que_function($req,$id);
558 0         0 while(my ($key,$value)=splice(@args,0,2)) {
559 0 0       0 if($key eq 'on_body') {
560             my $code=sub {
561 0     0   0 my ($body,$headers)=@_;
562 0         0 my $header=new HTTP::Headers( %{$headers});
  0         0  
563 0         0 $value->($self,$req,$header,$body);
564 0         0 };
565 0         0 $opt->{params}->{$key}=$code;
566             } else {
567 0         0 $opt->{params}->{$key}=$value;
568             }
569             }
570 0         0 $opt->{cb}=$code;
571             } else {
572 2         5 $req=$obj;
573 2         8 my $code=$self->que_function($req,$id);
574 2         6 $opt->{cb}=$code;
575             }
576 2         6 foreach my $key (qw(keepalive persistent)) {
577 4 100       14 $opt->{params}->{$key}=0 unless exists $opt->{params}->{$key};
578             }
579 2         9 my $request=$self->SENDER_CLASS->new(
580             $req,
581             $opt,
582             );
583              
584 2         273 return $request;
585             }
586              
587             =item * my $code=$self->que_function($req,$id);
588              
589             Internal method. Creates a code refrence for use in the que process.
590              
591             =cut
592              
593             sub que_function {
594 2     2 1 5 my ($self,$req,$id)=@_;
595 2         103 my $loop_id=$self->loop_id;
596              
597             my $code=sub {
598 2     2   17 my $response=$self->RESPONSE_CLASS->new(@_)->to_http_message;
599 2         276 $self->log_debug("Got Response for id: [$id] Status Line: ".$response->status_line);
600              
601             # work around for unit testing;
602 2 50       148 --$self->{que_count} if $self->{que_count} > 0;
603              
604 2 50 33     37 if(exists $self->retry->{$id} and $response->code > 594 and $self->retry->{$id}-- > 0) {
      33        
605 0         0 $self->log_info("Request negotiation error: ".$response->code." for id: $id retry count is: ".( 1 + $self->retry->{$id} )." will retry");
606 0         0 $self->add_by_id($id=>$req);
607 0         0 $self->run_next;
608 0         0 return;
609             }
610              
611 2         82 delete $self->retry->{$id};
612              
613 2 50       50 if(exists $self->running->{$id}) {
614 0         0 delete $self->running->{$id};
615             } else {
616 2         17 $self->log_debug("$id never ran, but the cb is being used");
617 2         68 $self->stack->remove($id);
618             }
619            
620 2         51 $self->results->{$id}=$self->new_true($response);
621            
622 2         258 $self->run_next;
623 2 50       1407 if($self->in_control_loop) {
624 0 0       0 if($self->que_count==0) {
625 0 0       0 $self->loop_control->send if $self->loop_control;
626             }
627 0         0 return;
628             }
629              
630 2 50       25 if($self->{que_count}==0) {
631 2         11 $self->log_debug('Que Count has reached 0');
632 2 50       96 if($loop_id!=$self->loop_id) {
633 0         0 $self->log_info("A result outside of it's lifecycle has arived loop_id: $loop_id que_id: $id, but we are in loop_id: ".$self->loop_id);
634 0         0 return;
635             }
636 2 50       28 $self->loop_control->send if $self->loop_control;
637             } else {
638 0         0 $self->log_debug("Que Count is at $self->{que_count}");
639             }
640              
641 2         32 };
642 2         5 return $code;
643             }
644              
645             =item * $self->block_loop
646              
647             Internal Function. Does a single timed pass against the current set of data, stops when the requests complete.
648              
649             =cut
650              
651             sub block_loop : BENCHMARK_DEBUG {
652 6         452 my ($self)=@_;
653 6         123 my $timeout=$self->timeout;
654 6         46 my $stack=$self->stack;
655 6         98 my $count=$self->que_count;
656              
657 6 50 33     51 return $self->new_true("No http requests in que") if($stack->total==0 and $count==0);
658              
659 0         0 my $result=$self->new_true();
660 0         0 $self->log_info("There are: $self->{que_count} jobs in the in the que");
661            
662 0         0 my $t;
663             LOOP_CONTROL: {
664 0         0 $self->in_control_loop(1);
  0         0  
665             # make sure we don't run forever!
666 0         0 $self->loop_control(AnyEvent->condvar);
667             $t=AnyEvent->timer(after=>$self->timeout,cb=>sub {
668 0         0 $result=$self->new_false("Timed out before we got a response");
669 0         0 $self->log_error("Request Que timed out, Que Count is: ".$self->que_count);
670 0         0 $self->loop_control->send;
671 0         0 });
672 0         0 $self->run_next;
673 0 0       0 $self->loop_control->send if $self->{que_count}<=0;
674              
675 0         0 $self->loop_control->recv;
676             }
677 0         0 $self->loop_control(undef);
678 0         0 undef $t;
679 0         0 $self->in_control_loop(0);
680 0         0 $self->loop_id($self->loop_id + 1);
681 0         0 return $result;
682 6     6   1826 }
  6         3798  
  6         48  
683              
684             =item * my @responses=$self->run_requests(@requests);
685              
686             Ques runs and blocks for all https requests, and returns the result objects
687              
688             Arguments:
689              
690             @requests: list of HTTP::Request Objects
691              
692             Responses
693              
694             @responses: list of HTTP::Result in order of the requests.
695              
696             =cut
697              
698             sub run_requests {
699 0     0 1 0 my ($self,@requests)=@_;
700 0         0 my @ids=$self->add(@requests);
701              
702 0         0 my $init_result=$self->block_for_ids(@ids);
703              
704 0         0 my @results;
705 0         0 my $results=$init_result->get_data;
706 0 0       0 if($init_result) {
707 0         0 foreach my $id (@ids) {
708 0         0 my $result=$results->{$id};
709 0 0       0 if($result) {
710 0         0 my $res=$result->get_data;
711 0         0 $res->code;
712 0         0 push @results,$res;
713             } else {
714 0         0 $self->log_debug("Failed to get response, error was: $init_result");
715 0         0 push @results,$self->RESPONSE_CLASS->new('',{Status=>500,Reason=>"Request Timed out"})->to_http_message;
716             }
717             }
718             } else {
719 0         0 foreach my $id (@ids) {
720 0         0 $self->log_debug("Failed to get response, error was: $init_result");
721 0         0 push @results,$self->RESPONSE_CLASS->new('',{Status=>500,Reason=>"Request Timed out"})->to_http_message;
722             }
723             }
724 0         0 return @results;
725             }
726              
727             =item * $self->clean_results
728              
729             Used to remove any results that are unclaimed ( Use to prevent memory leaks! ).
730              
731             =cut
732              
733             sub clean_results {
734 0     0 1 0 %{$_[0]->results}=();
  0         0  
735             }
736              
737             =item * my @responses=$self->block_for_results_by_id(@ids)
738              
739             Blocks on the @ids lsit for list of HTTP::Response objects
740              
741             =cut
742              
743             sub block_for_results_by_id {
744 6     6 1 67 my ($self,@ids)=@_;
745              
746 6         23 my $result=$self->block_for_ids(@ids);
747              
748 6         12 my @results;
749 6 100       19 if($result) {
750 2         159 my $hash=$result->get_data;
751 2         12 foreach my $id (@ids) {
752 2         4 my $result=$hash->{$id};
753 2 50       5 if($result) {
754 2         119 push @results,$result->get_data;
755             } else {
756 0         0 push @results,$self->RESPONSE_CLASS->new('',{Status=>500,Reason=>"Request Timed out"})->to_http_message;
757             }
758             }
759              
760             } else {
761 4         198 foreach my $id (@ids) {
762 4         43 push @results,$self->RESPONSE_CLASS->new('',{Status=>500,Reason=>"Request Timed out"})->to_http_message;
763             }
764             }
765              
766 6         754 return @results;
767             }
768              
769             =item * my @results=$self->get_results(@ids);
770              
771             Does not block, just returns a list of HTTP::Response objects based on @ids
772              
773             =cut
774              
775             sub get_results {
776 0     0 1   my ($self,@ids)=@_;
777              
778 0           my $result=$self->new_false('request does not exist!');
779              
780 0           my @results;
781 0           my $ok=0;
782 0           foreach my $id (@ids) {
783 0 0         if(exists $self->results->{$id}) {
784 0           ++$ok;
785 0           my $result=$self->results->{$id};
786 0           delete $self->results->{$id};
787 0 0         if($result) {
788 0           push @results,$result->get_data;
789             } else {
790 0           push @results,$self->RESPONSE_CLASS->new('',{Status=>500,Reason=>"Request Timed out"})->to_http_message;
791             }
792             } else {
793 0           push @results,$self->RESPONSE_CLASS->new('',{Status=>500,Reason=>"Request Timed out"})->to_http_message;
794             }
795             }
796            
797 0           return @results;
798             }
799              
800             =back
801              
802             =head1 Using with AnyEvent
803              
804             See L<AnyEvent::HTTP::MultiGet>
805              
806             =head1 AUTHOR
807              
808             Mike Shipper L<mailto:AKALINUX@CPAN.ORG>
809              
810             =cut
811              
812             1