File Coverage

blib/lib/Mojolicious/Plugin/ForkCall.pm
Criterion Covered Total %
statement 25 25 100.0
branch 5 6 83.3
condition 2 3 66.6
subroutine 5 5 100.0
pod 1 1 100.0
total 38 40 95.0


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::ForkCall;
2              
3 1     1   792 use Mojo::Base 'Mojolicious::Plugin';
  1         2  
  1         6  
4              
5 1     1   589 use Mojo::IOLoop::ForkCall;
  1         2  
  1         36  
6 1     1   6 use Carp;
  1         2  
  1         349  
7             our @CARP_NOT = qw/Mojolicious Mojolicious::Controller/;
8              
9             sub register {
10 1     1 1 37 my ($self, $app) = @_;
11              
12             $app->helper(fork_call => sub {
13 5     5   177443 my $c = shift;
14 5 100 66     36 unless (@_ > 1 and ref $_[-1] eq 'CODE') {
15 1         381 croak 'fork_call helper must be passed a callback';
16             }
17              
18 4         10 my $cb = pop;
19 4         8 my @args = @_;
20              
21             $c->delay(
22             sub{
23 4         1794 my $end = shift->begin;
24 4 50       38 my $once = sub { $end->(@_) if $end; undef $end };
  4         40  
  4         2681  
25 4         41 Mojo::IOLoop::ForkCall->new
26             ->catch($once)
27             ->run(@args, $once);
28             },
29             sub {
30 4         143 my ($delay, $err, @return) = @_;
31 4 100       20 die $err if $err;
32 2         15 $c->$cb(@return);
33             }
34 4         51 );
35 1         21 });
36             }
37              
38             1;
39              
40             =head1 NAME
41              
42             Mojolicious::Plugin::ForkCall - run blocking code asynchronously in Mojolicious
43             applications by forking
44              
45             =head1 SYNOPSIS
46              
47             use Mojolicious::Lite;
48              
49             plugin 'Mojolicious::Plugin::ForkCall';
50              
51             get '/slow' => sub {
52             my $c = shift;
53             my @args = ...;
54             $c->fork_call(
55             sub {
56             my @args = @_;
57             return do_slow_stuff(@args);
58             },
59             [@args],
60             sub {
61             my ($c, @return) = @_;
62             $c->render(json => \@return);
63             }
64             );
65             };
66              
67             ...
68              
69             app->start;
70              
71             =head1 DESCRIPTION
72              
73             Registering L adds a helper method C
74             to your L application, making it easy to start code in a forked
75             process using L.
76              
77             Note that it does not increase the timeout of the connection, so if your
78             forked process is going to take a very long time, you might need to increase
79             that using L.
80              
81             =head1 HELPERS
82              
83             This module adds the following helper method to your application:
84              
85             =head2 fork_call
86              
87             $c->fork_call(
88             sub {
89             my @args = @_;
90             # This code is run in a forked process
91             return @return;
92             },
93             [$arg1, $arg2, $arg3], # Optional arguments passed to the above code
94             sub {
95             my ($c, @return) = @_;
96             # This code is run in the current process once the child exits
97             }
98             );
99              
100             The C helper takes up to 3 arguments: a required code reference to
101             be run in a forked child process, an optional array reference of arguments to
102             be passed to the child code, and a required code reference to be run in the
103             parent as a callback. The callback is passed the controler instance and return
104             values of the child.
105              
106             The helper relies on the L core helper
107             L and as such it will render an
108             exception (500) page if any uncaught exception occurs in the child process or
109             in the parent callback. This also means that the parent callback will not be
110             called if the child process encounters an exception.
111              
112             This helper is a convenience only and is not indended for complex cases.
113             If you need to configure the L instance or want to
114             "fork and forget" a child, you should use the class directly rather than this
115             helper. If more complicated delays are required, you should use the
116             L helper or L
117             method directly, along with an instance of L.
118              
119             =cut
120