Forráskód Böngészése

Actually do autoreload correctly, needed to wrap plack::loader

George Baugh 5 hónapja
szülő
commit
b3820e7151
4 módosított fájl, 81 hozzáadás és 24 törlés
  1. 45 0
      bin/tarbaby
  2. 1 3
      bin/tpsgi
  3. 34 20
      lib/TPSGI.pm
  4. 1 1
      service/tpsgi.sh

+ 45 - 0
bin/tarbaby

@@ -0,0 +1,45 @@
+#!/usr/bin/env perl
+
+# Minor modifications to starman to support autoreload of code without Plack::Loader::Restarter.
+
+use strict;
+
+use FindBin::libs;
+use Plack::Runner;
+
+use File::Basename qw{dirname};
+use TPSGI;
+
+sub version {
+    require Starman;
+    print "Starman $Starman::VERSION\n";
+}
+
+# Setup the watcher for changes
+# This has to be setup at global server start rather than app start per worker.
+# This is preferable to using -R (Plack::Loader::Restarter, see notes in orig starman)
+my %options = TPSGI::get_config();
+my @dirs = ("$options{tpsgi_dir}/lib");
+foreach my $route (@{$options{routers}}) {
+    push(@dirs, dirname("$options{tpsgi_dir}/$route"));
+}
+TPSGI::watch_for_changes(@dirs);
+
+my $preload_app;
+require Getopt::Long;
+Getopt::Long::Configure("no_ignore_case", "no_auto_abbrev", "pass_through");
+Getopt::Long::GetOptions(
+    "preload-app"      => \$preload_app,
+);
+
+my @args = (server => 'Starman', env => 'deployment', version_cb => \&version);
+if (!$preload_app) {
+        push @args, 'loader' => 'Delayed';
+}
+my @argv = @ARGV;
+my $runner = Plack::Runner->new(@args);
+$runner->parse_options(@argv);
+
+$runner->set_options(argv => \@argv);
+$runner->run;
+

+ 1 - 3
bin/tpsgi

@@ -1,6 +1,4 @@
-#!/usr/bin/env starman
-
-#pacakge bin::tpsgi;
+#!bin/tarbaby
 
 #ABSTRACT: PSGI application which simplifies migrating legacy/cgi applications to PSGI, but also has advanced features for normal psgi apps
 

+ 34 - 20
lib/TPSGI.pm

@@ -33,7 +33,9 @@ use URL::Encode();
 use File::Touch;
 use File::Path;
 use File::Copy;
+use File::Find;
 use Cwd            qw{abs_path};
+
 use File::Basename qw{dirname basename};
 use Log::Dispatch;
 use Log::Dispatch::Screen;
@@ -224,9 +226,6 @@ sub new {
     my @routes;
     my %aliases;
 
-    # Setup inotify watchers to know if we need to reload the application after this request.
-    $self->_watch_for_changes("$options{tpsgi_dir}/lib");
-
     # XXX TODO make these routes able to be fully qualified namespaces (::)!
     no strict 'refs';
     foreach my $route ( @{ $self->{routers} } ) {
@@ -242,8 +241,6 @@ sub new {
         my $libdir = dirname("$options{tpsgi_dir}/$route");
         push( @INC, $libdir );
 
-        $self->_watch_for_changes($libdir);
-
         local $@;
         $self->DEBUG("require $options{tpsgi_dir}/$route");
         my $success = eval { require "$options{tpsgi_dir}/$route"; 1; };
@@ -1260,24 +1257,34 @@ sub invalidate_render {
     unlink "$file";
 }
 
-sub _watch_for_changes {
-    my ($self, @dirs) = @_;
+my @wds;
+my $inotify;
+sub watch_for_changes {
+    my (@dirs) = @_;
+
+    # No point watching again if we already are watching
+    return if @wds;
 
-    $self->{wds} //= [];
+    $inotify //= Linux::Perl::inotify->new(flags => [qw{NONBLOCK}]);
+    my @to_watch =_readdir( @dirs );
 
-    $self->{inf} //= Linux::Perl::inotify->new(flags => [qw{NONBLOCK}]);
-    foreach my $directory (@dirs) {
-        # Recursive scan for directories and setting up inotifies
-        push(@dirs, _readdir( $directory ));
-        $self->INFO( "Watching $directory for changes\n" );
-        push(@{$self->{wds}}, $self->{inf}->add( path => $directory, events => [qw{CREATE MODIFY}] ));
+    foreach my $f2watch (@to_watch) {
+        print "Watching $f2watch for changes\n";
+        push(@wds, $inotify->add( path => $f2watch, events => [qw{CREATE MODIFY DELETE MOVE}] ));
     }
 }
 
+=head2 restart_if_changes
+
+Restart tPSGI if any of the relevant libdir files change.
+Powers the autorestart feature.
+
+=cut
+
 sub restart_if_changes {
     my $self = shift;
 
-    my @result = $self->{inf}->read();
+    my @result = $inotify->read();
     my $had_changes = 0;
 
     foreach my $res (@result) {
@@ -1286,18 +1293,25 @@ sub restart_if_changes {
             last;
         }
     }
+    return 0 unless $had_changes ;
 
+    # We don't have to clean up the wds, that is handled in the destructor for Inotify
     $self->INFO("Relevant Change in libdirs detected, reloading\n");
-    foreach my $wd (@{$self->{wds}}) { $self->{inf}->remove($wd) }
     $self->signal_restart_parent();
     return 0;
 }
 
 sub _readdir {
-    my $dir = shift;
-    opendir(my $dh, $dir);
-    my @dirs = map { "$dir/$_" } grep { -d "$dir/$_" && !m/^\.+$/ } readdir($dh);
-    closedir($dh);
+    my @dirs = @_;
+    File::Find::find( {
+        wanted => sub {
+            my $object = $_;
+            push(@dirs, $object) if (-f $object && $object =~ m/\.pm$/);
+        },
+        no_chdir => 1,
+        bydepth => 1,
+    },
+    @dirs);
     return @dirs;
 }
 

+ 1 - 1
service/tpsgi.sh

@@ -30,7 +30,7 @@ for bind in "${BIND_DIRS[@]}"; do
 done
 
 # We should obey the PATH set by this user, whose homedir is right here, ideally.
-bin/tpsgi --listen run/tpsgi.sock --workers 20 --user "$USERNAME" --group "$GROUP" --daemonize --pid run/tpsgi.pid --chroot $(pwd)
+bin/tarbaby --listen run/tpsgi.sock --workers 20 --user "$USERNAME" --group "$GROUP" --daemonize --pid run/tpsgi.pid --chroot $(pwd) bin/tpsgi
 
 if [ $? -ne 0 ]
 then