File Coverage

blib/lib/Mojo/IOLoop/ProcBackground.pm
Criterion Covered Total %
statement 9 13 69.2
branch 0 2 0.0
condition 1 2 50.0
subroutine 3 4 75.0
pod 0 1 0.0
total 13 22 59.0


line stmt bran cond sub pod time code
1             package Mojo::IOLoop::ProcBackground;
2              
3 1     1   108605 use Mojo::Base 'Mojo::EventEmitter';
  1         24652  
  1         79  
4              
5 1     1   7810 use Proc::Background;
  1         13404  
  1         61  
6              
7             #
8             # Thanks to Mojo::IOLoop::ReadWriteFork and Mojo::IOLoop::ForkCall
9             #
10              
11 1   50 1   13 use constant DEBUG => $ENV{MOJO_PROCBACKGROUND_DEBUG} || 0;
  1         7  
  1         340  
12              
13             our $VERSION = '0.04';
14              
15             =head1 NAME
16              
17             Mojo::IOLoop::ProcBackground - IOLoop interface to Proc::Background
18              
19             =head1 VERSION
20              
21             0.04
22              
23             =head1 DESCRIPTION
24              
25             This is an IOLoop interface to Proc::Background.
26              
27             From Proc::Background:
28              
29             This is a generic interface for placing processes in the background on both Unix and
30             Win32 platforms. This module lets you start, kill, wait on, retrieve exit values, and
31             see if background processes still exist.
32              
33              
34             =head1 SYNOPSIS
35              
36             use Mojolicious::Lite;
37              
38             use Mojo::IOLoop::ProcBackground;
39              
40             use File::Temp;
41             use File::Spec;
42             use Proc::Background;
43              
44             any '/run' => sub {
45             my $self = shift;
46              
47             # Setup our request to take a while
48             Mojo::IOLoop->stream($self->tx->connection)->timeout(30);
49             $self->render_later;
50              
51             $self->on(finish => sub {
52             $self->app->log->debug("Finished");
53             });
54              
55             # We want the UserAgent to see something as soon as possible
56             $self->res->code(200);
57             $self->res->headers->content_type('text/html');
58             $self->write_chunk("Starting...
\n");
59              
60             # This is our utility script that will run in the background
61             my $tmp = File::Temp->new(UNLINK => 0, SUFFIX => '.pl');
62             my $statefile = $self->stash->{_statefile} = File::Spec->catfile(File::Spec->tmpdir, "done");
63             print($tmp 'sleep(10); $f="$ARGV[0].$$"; open($fh, ">", $f); sleep(3)');
64             my $script = $tmp->filename;
65             undef($tmp);
66              
67             # Thanks CPAN.. :) The magic happens in Proc::Background
68             my $proc = $self->stash->{_proc} = Mojo::IOLoop::ProcBackground->new;
69              
70             # Every so often we get a heartbeat from the background process
71             $proc->on(alive => sub {
72             my ($proc) = @_;
73              
74             my $pid = $proc->proc->pid;
75             my $statefile = $self->stash->{_statefile} . ".$pid";
76              
77             if (-f $statefile) {
78             $self->write_chunk("Done");
79             $proc->unsubscribe("alive");
80             }
81             });
82              
83             # When the process terminates, we get this event
84             $proc->on(dead => sub {
85             my ($proc) = @_;
86              
87             my $pid = $proc->proc->pid;
88             my $statefile = $self->stash->{_statefile} . ".$pid";
89              
90             $self->app->log->debug("Done: $statefile");
91             $self->finish;
92             });
93              
94             # Start our process
95             $proc->run([$^X, $script, $statefile]);
96             };
97              
98             # Run the app
99             push(@ARGV, 'daemon', '-l', 'http://*:5555') unless @ARGV;
100             app->log->level("debug");
101             app->secrets(["I Knos# you!!"]);
102             app->start;
103              
104             =head2 SEE ALSO
105              
106             =over
107              
108             =item L
109              
110             =item L
111              
112             =back
113              
114             =cut
115              
116             # Thanks jberger.. :)
117              
118             has 'command';
119              
120             has proc => sub {
121             my $command = shift->command;
122             Proc::Background->new(ref($command) ? @{ $command } : $command);
123             };
124              
125             has recurring => sub {
126             my $self = shift;
127             Mojo::IOLoop->recurring(0.05 => sub {
128             if ($self->proc->alive) {
129             $self->emit_safe("alive");
130             }
131             else {
132             Mojo::IOLoop->remove($self->recurring);
133             $self->emit_safe("dead");
134             }
135             });
136             };
137              
138             sub run {
139 0     0 0   my $self = shift;
140 0 0         $self->command(shift) if @_;
141 0           $self->proc; # build proc
142 0           $self->recurring; # start watching it
143             }
144              
145             1;