Reputation: 1309
I'm trying to write a a perl-based webserver using Twiggy::Server
(which means a plack app).
I want to respond to a request (coming from an ajax call on a webpage) for some data by running some possibly time-consuming subroutine which generates the data and then turns it into a JSON string for returning to the client webpage.
You can see a cut-down test version of my server here: http://pastebin.com/iNaDTVwL
That example shows the problem I'm facing with my current implementation; using AnyEvent::ForkManager
to do the non-blocking part of things results in truncation of the 'big' json response.
This document would answer my questions perfectly (and better explains what I'm trying to do): https://github.com/jjn1056/Example-PlackStreamingAndNonblocking ... if it was finished. I'm just missing the 'proper' way of doing non-blocking, instead of using AnyEvent::ForkManager
which seems like a bit of a hack.
Upvotes: 0
Views: 958
Reputation: 8542
Personally I'd use Net::Async::HTTP::Server::PSGI
. From its SYNOPSIS:
use Net::Async::HTTP::Server::PSGI;
use IO::Async::Loop;
my $loop = IO::Async::Loop->new;
my $httpserver = Net::Async::HTTP::Server::PSGI->new(
app => sub {
my $env = shift;
return [
200,
[ "Content-Type" => "text/plain" ],
[ "Hello, world!" ],
];
},
);
$loop->add( $httpserver );
$httpserver->listen(
addr => { family => "inet6", socktype => "stream", port => 8080 },
on_listen_error => sub { die "Cannot listen - $_[-1]\n" },
);
$loop->run;
Obviously this particularly tiny example doesn't demonstrate anything asynchronous, but you have full access to all of the IO::Async
system in order to defer and respond later.
Upvotes: 1
Reputation: 53508
So following on from the comments - I don't know enough about the things you're using to give you a specific response, but can offer up something generic.
Using threads to 'async' part of your Perl script:
#!/usr/bin/perl
use strict;
use warnings;
use threads;
use Thread::Queue;
my $input_q = Thread::Queue -> new();
my $success_q = Thread::Queue -> new();
my $failure_q = Thread::Queue -> new();
my $thread_count = 4;
sub spinoff_thread {
while ( my $target = $input_q -> dequeue() )
{
#do something to $target
my @results = `ping -c 10 -i 1 $target`;
if ( $? ) {
$failure_q -> enqueue ( $target );
}
else {
$success_q -> enqueue ( $target );
}
}
}
#main bit
for ( 1..$thread_count ) {
my $thr = threads -> create ( \&spinoff_thread );
}
foreach my $server ( "server1", "server2", "server3", "server4", "server5" ) {
$input_q -> enqueue ( $server );
}
$input_q -> end(); #will cause threads to 'bail out' because that while loop will go 'undef');
#wait for threads to complete.
foreach my $thr ( threads -> list() ) {
$thr -> join();
}
print "Fail:\n", join ("\n", $failure_q -> dequeue() ), "\n";
print "Success:\n"; join ( "\n", $success_q -> dequeue() ), "\n";
The key points being that your threads - are basically subroutines - and can pass things back and forth using the Queues. end
the queue is a good way to handle telling a thread to terminate - there are other ways of course.
Upvotes: 0