Capturing the output of Multiple parallel http requests
Ian Stuart
Ian.Stuart at ed.ac.uk
Fri Jan 28 13:30:13 CET 2011
I'm trying to make http post-requests to a number of hosts.
I can do this sequentially, however that solution does not scale, so I
am re-implementing in a parallel mode... using AnyEvent::HTTP
(In the environment I will use this, the number of POST requests is
variable, hence the use of a loop rather than any attempt to just set up
a sequential just as in the "finger" example in AnyEvent::Intro)
I can fire off multiple requests, and I can see the response from each
of those queries.... but I can't get my head round how to return those
responses back to my core code.
My references for this are the documentation for AnyEvent,
AnyEvent::HTTP and AnyEvent::Intro - the info is, I think, there... I
just can't piece it all together to make it work
My code:
------- start code ------
#!/path/to/bin/perl -w
use strict;
use Event;
use AnyEvent::HTTP;
use AnyEvent::Strict;
use MIME::Base64;
use Data::Dumper;
my @targets = qw(host1 host2 host3 host4 host4);
my ($host, $username, $password, $realm, $sword_url, $collection) = ();
my $endpoints = {};
# code deleted for making actual connections, but they look like this:
#$endpoints->{'nost_n'} = {};
#$endpoints->{'host_n'}->{'host'} = 'the.host.name';
#$endpoints->{'host_n'}->{'collection'} = '/path/to/location';
#$endpoints->{'host_n'}->{'username'} = 'l-user';
#$endpoints->{'host_n'}->{'password'} = 'pa$$wrd';
# file to send via POST:
my $zipfile = "broker_deposit.zip"; # A DSpace/Mets zip file
# An AnyEvent method to send a zip file to a sword endpoint
#
sub transfer($)
{
my ($params) = @_;
my ($file, $host, $collection, $username, $password, $protocol);
# delete on a hash element returns undef if that key does not exist,
# therefor that scalar is set to undef if the parameter is not
# passed into the method
$file = delete $params->{file};
$host = delete $params->{host};
$protocol = delete $params->{protocol};
$collection = delete $params->{collection};
$username = delete $params->{username};
$password = delete $params->{password};
# Load the file. If there is no file, then return from the event
# with nothing
my $archive = "";
open(FILE, $file)
or return "Unable to create Transfer package";
binmode FILE;
while (my $l = <FILE>) { $archive .= $l; }
close FILE;
# Tell SWORD to process the contents of the zip file as the new OA-RJ
# type
my $auth = "Basic ".MIME::Base64::encode("$username:$password", '');
my %headers = (
'X-Packaging' => 'http://opendepot.org/broker/1.0',
'X-No-Op' => 'false',
'X-Verbose' => 'false',
'Content-Disposition' => "filename=$file",
'Content-Type' => 'application/zip',
'User::Agent' => 'OA-RJ Broker v0.2',
'Authorization' => $auth,
);
my $myReturn;
# this is a long call, intersperced with comments!
$myReturn = http_request(
# the main request we want to make
"POST", "http://${host}${collection}",
# the body of the http_request
body => $archive,
# the headers for that request
headers => \%headers,
# The routine called on Error or on completion
sub {
my ($body, $header) = @_;
my $text = "";
if ($header->{Status} =~ /^2\d{2}/)
{
$text = $body;
} else
{
$text = "Error: ".$header->{Status}.":
".$header->{Reason}."\n";
}
print "body: $text\n";
return $text
}
);
print "returning: ".Dumper ($myReturn);
return $myReturn;
} ## end sub transfer($$)
my %responses;
my $cv = AnyEvent->condvar;
foreach my $target (@targets)
{
my %params = (
protocol => 'http',
host => delete $endpoints->{$target}->{'host'},
collection => delete $endpoints->{$target}->{'collection'},
username => delete $endpoints->{$target}->{'username'},
password => delete $endpoints->{$target}->{'password'},
file => $zipfile,
);
$responses{$target} = transfer( \%params,);
} ## end foreach my $target (@targets...)
for my $response ( keys %responses ){
print "$response ", $cv->recv, "\n";
}
$cv = undef;
print Dumper(\@responses);
exit;
---------- end code --------------
The script runs, with the following output:
----- start output ------
body: Error: 401: Unauthorized
body: Error: 401: Unauthorized
body: Error: 415: Unsupported Media Type
body: <?xml version="1.0" encoding="UTF-8"?><atom:entry
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sword="http://purl.org/net/sword/">
// <!-- snip -->
</atom:entry>
body: <?xml version="1.0" encoding="UTF-8"?><atom:entry
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sword="http://purl.org/net/sword/">
// <!-- snip -->
</atom:entry>
----- end output -----
This shows me that I'm getting correct responses for each http_request,
however I'm just not passing them back.
I'm sure I have the right general idea, but the details are eluding me :(
How do I run a bunch of queries, and then capture each response?
--
Ian Stuart.
Developer: Open Access Repository Junction and OpenDepot.org
Bibliographics and Multimedia Service Delivery team,
EDINA,
The University of Edinburgh.
http://edina.ac.uk/
This email was sent via the University of Edinburgh.
The University of Edinburgh is a charitable body, registered in
Scotland, with registration number SC005336.
More information about the anyevent
mailing list